diff --git a/cpp/core/BUILD b/cpp/core/BUILD index 9491718c..1e5c1d42 100644 --- a/cpp/core/BUILD +++ b/cpp/core/BUILD @@ -1,24 +1,29 @@ cc_library( name = "core", - hdrs = [ + srcs = [ "core.cc", + ], + hdrs = [ "core.h", ], visibility = [ - "//googlemac/iPhone/Shared/Nearby/Connections:__pkg__", - "//location/nearby/setup/core/internal:__pkg__", + "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", ], deps = [ - ":types", + ":core_types", "//core/internal", - "//platform:types", + "//platform/public:comm", + "//platform/public:logging", + "//platform/public:types", + "//absl/strings", + "//absl/time", + "//absl/types:span", ], ) cc_library( - name = "types", + name = "core_types", srcs = [ - "payload.cc", "strategy.cc", ], hdrs = [ @@ -30,29 +35,43 @@ cc_library( "strategy.h", ], visibility = [ - "//core/internal:__pkg__", - "//location/nearby/setup/core/internal:__pkg__", + "//core:__subpackages__", ], deps = [ - "//platform:types", - "//platform:utils", - "//platform/api", - "//platform/port:string", + "//platform/base", + "//platform/public:comm", + "//platform/public:logging", + "//platform/public:types", + "//proto:connections_enums_portable_proto", + "//absl/strings", + "//absl/types:variant", ], ) -cc_library( - name = "check_compilation", - srcs = ["check_compilation.cc"], +cc_test( + name = "core_test", + size = "small", + srcs = [ + "core_test.cc", + "listeners_test.cc", + "payload_test.cc", + "status_test.cc", + "strategy_test.cc", + ], + shard_count = 16, deps = [ ":core", - ":types", - "//platform:types", - "//platform:utils", - "//platform/api", - "//platform/impl/g3", - "//platform/impl/shared:file", - "//platform/impl/shared/sample:sample_wifi_medium", - "//platform/port:string", + ":core_types", + "//core/internal", + "//core/internal:internal_test", + "//platform/base", + "//platform/impl/g3", # build_cleaner: keep + "//platform/public:comm", + "//platform/public:logging", + "//platform/public:types", + "//testing/base/public:gunit_main", + "//absl/strings", + "//absl/time", + "//absl/types:variant", ], ) diff --git a/cpp/core/check_compilation.cc b/cpp/core/check_compilation.cc deleted file mode 100644 index 584c6cb4..00000000 --- a/cpp/core/check_compilation.cc +++ /dev/null @@ -1,121 +0,0 @@ -#include - -#include "core/core.h" -#include "core/listeners.h" -#include "core/params.h" -#include "core/payload.h" -#include "core/status.h" -#include "platform/api/platform.h" -#include "platform/byte_array.h" -#include "platform/impl/shared/file_impl.h" -#include "platform/impl/shared/sample/sample_wifi_medium.h" -#include "platform/port/string.h" -#include "platform/ptr.h" - -namespace location { -namespace nearby { -namespace connections { - -using TestPlatform = platform::ImplementationPlatform; - -class ResultListenerImpl : public ResultListener { - public: - void onResult(Status::Value status) override {} -}; - -class ConnectionLifecycleListenerImpl : public ConnectionLifecycleListener { - public: - void onConnectionInitiated(ConstPtr - on_connection_initiated_params) override {} - void onConnectionResult( - ConstPtr on_connection_result_params) override { - } - void onDisconnected( - ConstPtr on_disconnected_params) override {} - void onBandwidthChanged( - ConstPtr on_bandwidth_changed_params) override { - } -}; - -class DiscoveryListenerImpl : public DiscoveryListener { - public: - void onEndpointFound( - ConstPtr on_endpoint_found_params) override {} - void onEndpointLost( - ConstPtr on_endpoint_lost_params) override {} -}; - -class PayloadListenerImpl : public PayloadListener { - public: - void onPayloadReceived( - ConstPtr on_payload_received_params) override {} - void onPayloadTransferUpdate(ConstPtr - on_payload_transfer_update_params) override { - } -}; - -void check_compilation() { - Core core; - - const string name = "name"; - const string service_id = "service_id"; - const string remote_endpoint_id = "remote_endpoint_id"; - - core.startAdvertising(MakeConstPtr(new StartAdvertisingParams( - MakePtr(new ResultListenerImpl()), name, service_id, - AdvertisingOptions(Strategy::kP2PCluster, - /* auto_upgrade_bandwidth= */ false, - /* enforce_topology_constraints= */ false), - MakePtr(new ConnectionLifecycleListenerImpl())))); - - core.stopAdvertising(MakeConstPtr(new StopAdvertisingParams())); - - core.startDiscovery(MakeConstPtr( - new StartDiscoveryParams(MakePtr(new ResultListenerImpl()), service_id, - DiscoveryOptions(Strategy::kP2PCluster), - MakePtr(new DiscoveryListenerImpl())))); - - core.stopDiscovery(MakeConstPtr(new StopDiscoveryParams())); - - core.requestConnection(MakeConstPtr(new RequestConnectionParams( - MakePtr(new ResultListenerImpl()), name, remote_endpoint_id, - MakePtr(new ConnectionLifecycleListenerImpl())))); - - core.acceptConnection(MakeConstPtr(new AcceptConnectionParams( - MakePtr(new ResultListenerImpl()), remote_endpoint_id, - MakePtr(new PayloadListenerImpl())))); - - core.rejectConnection(MakeConstPtr(new RejectConnectionParams( - MakePtr(new ResultListenerImpl()), remote_endpoint_id))); - - core.initiateBandwidthUpgrade(MakeConstPtr(new InitiateBandwidthUpgradeParams( - MakePtr(new ResultListenerImpl()), remote_endpoint_id))); - - core.sendPayload(MakeConstPtr(new SendPayloadParams( - MakePtr(new ResultListenerImpl()), - std::vector(1, remote_endpoint_id), - ConstifyPtr( - Payload::fromBytes(MakeConstPtr(new ByteArray("bytes", 5))))))); - - core.cancelPayload(MakeConstPtr( - new CancelPayloadParams(MakePtr(new ResultListenerImpl()), 1))); - - core.sendPayload(MakeConstPtr(new SendPayloadParams( - MakePtr(new ResultListenerImpl()), - std::vector(2, remote_endpoint_id), - ConstifyPtr(Payload::fromFile(MakePtr( - new InputFileImpl("/some/arbitrary/file/path.txt", 1024))))))); - - core.cancelPayload(MakeConstPtr( - new CancelPayloadParams(MakePtr(new ResultListenerImpl()), 2))); - - core.disconnectFromEndpoint( - MakeConstPtr(new DisconnectFromEndpointParams(remote_endpoint_id))); - - core.stopAllEndpoints(MakeConstPtr( - new StopAllEndpointsParams(MakePtr(new ResultListenerImpl())))); -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core/core.cc b/cpp/core/core.cc index 8409d0cc..6a2f33cc 100644 --- a/cpp/core/core.cc +++ b/cpp/core/core.cc @@ -1,135 +1,114 @@ #include "core/core.h" #include +#include + +#include "core/options.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/logging.h" +#include "absl/time/clock.h" namespace location { namespace nearby { namespace connections { -template -Core::Core() - : client_proxy_(new ClientProxy()), - service_controller_router_(new ServiceControllerRouter()) {} +constexpr absl::Duration Core::kWaitForDisconnect; -template -Core::~Core() { - service_controller_router_->clientDisconnecting(client_proxy_.get()); +Core::~Core() { + CountDownLatch latch(1); + router_.ClientDisconnecting( + &client_, { + .result_cb = [&latch](Status) { latch.CountDown(); }, + }); + if (!latch.Await(kWaitForDisconnect).result()) { + NEARBY_LOG(FATAL, "Unable to shutdown"); + } } -template -void Core::startAdvertising( - ConstPtr start_advertising_params) { - assert(!start_advertising_params->result_listener.isNull()); - assert(!start_advertising_params->connection_lifecycle_listener.isNull()); - assert(!start_advertising_params->service_id.empty()); - assert(start_advertising_params->advertising_options.strategy.isValid()); +void Core::StartAdvertising(absl::string_view service_id, + ConnectionOptions options, + ConnectionRequestInfo info, + ResultCallback callback) { + assert(!service_id.empty()); + assert(options.strategy.IsValid()); - service_controller_router_->startAdvertising(client_proxy_.get(), - start_advertising_params); + router_.StartAdvertising(&client_, service_id, options, info, callback); } -template -void Core::stopAdvertising( - ConstPtr stop_advertising_params) { - service_controller_router_->stopAdvertising(client_proxy_.get(), - stop_advertising_params); +void Core::StopAdvertising(const ResultCallback callback) { + router_.StopAdvertising(&client_, callback); } -template -void Core::startDiscovery( - ConstPtr start_discovery_params) { - assert(!start_discovery_params->result_listener.isNull()); - assert(!start_discovery_params->discovery_listener.isNull()); - assert(!start_discovery_params->service_id.empty()); - assert(start_discovery_params->discovery_options.strategy.isValid()); +void Core::StartDiscovery(absl::string_view service_id, + ConnectionOptions options, DiscoveryListener listener, + ResultCallback callback) { + assert(!service_id.empty()); + assert(options.strategy.IsValid()); - service_controller_router_->startDiscovery(client_proxy_.get(), - start_discovery_params); + router_.StartDiscovery(&client_, service_id, options, listener, callback); } -template -void Core::stopDiscovery( - ConstPtr stop_discovery_params) { - service_controller_router_->stopDiscovery(client_proxy_.get(), - stop_discovery_params); +void Core::InjectEndpoint(absl::string_view service_id, + OutOfBandConnectionMetadata metadata, + ResultCallback callback) { + router_.InjectEndpoint(&client_, service_id, metadata, callback); } -template -void Core::requestConnection( - ConstPtr request_connection_params) { - assert(!request_connection_params->result_listener.isNull()); - assert(!request_connection_params->connection_lifecycle_listener.isNull()); - assert(!request_connection_params->remote_endpoint_id.empty()); - - service_controller_router_->requestConnection(client_proxy_.get(), - request_connection_params); +void Core::StopDiscovery(ResultCallback callback) { + router_.StopDiscovery(&client_, callback); } -template -void Core::acceptConnection( - ConstPtr accept_connection_params) { - assert(!accept_connection_params->result_listener.isNull()); - assert(!accept_connection_params->payload_listener.isNull()); - assert(!accept_connection_params->remote_endpoint_id.empty()); +void Core::RequestConnection(absl::string_view endpoint_id, + ConnectionRequestInfo info, + ConnectionOptions options, + ResultCallback callback) { + assert(!endpoint_id.empty()); - service_controller_router_->acceptConnection(client_proxy_.get(), - accept_connection_params); + router_.RequestConnection(&client_, endpoint_id, info, options, callback); } -template -void Core::rejectConnection( - ConstPtr reject_connection_params) { - assert(!reject_connection_params->result_listener.isNull()); - assert(!reject_connection_params->remote_endpoint_id.empty()); +void Core::AcceptConnection(absl::string_view endpoint_id, + PayloadListener listener, ResultCallback callback) { + assert(!endpoint_id.empty()); - service_controller_router_->rejectConnection(client_proxy_.get(), - reject_connection_params); + router_.AcceptConnection(&client_, endpoint_id, listener, callback); } -template -void Core::initiateBandwidthUpgrade( - ConstPtr - initiate_bandwidth_upgrade_params) { - service_controller_router_->initiateBandwidthUpgrade( - client_proxy_.get(), initiate_bandwidth_upgrade_params); +void Core::RejectConnection(absl::string_view endpoint_id, + ResultCallback callback) { + assert(!endpoint_id.empty()); + + router_.RejectConnection(&client_, endpoint_id, callback); } -template -void Core::sendPayload( - ConstPtr send_payload_params) { - assert(!send_payload_params->result_listener.isNull()); - assert(!send_payload_params->remote_endpoint_ids.empty()); - assert(!send_payload_params->payload.isNull()); - // TODO(tracyzhou): Do sanity check on payload based on payload type. - - service_controller_router_->sendPayload(client_proxy_.get(), - send_payload_params); +void Core::InitiateBandwidthUpgrade(absl::string_view endpoint_id, + ResultCallback callback) { + router_.InitiateBandwidthUpgrade(&client_, endpoint_id, callback); } -template -void Core::cancelPayload( - ConstPtr cancel_payload_params) { - assert(!cancel_payload_params->result_listener.isNull()); - assert(cancel_payload_params->payload_id != 0); +void Core::SendPayload(absl::Span endpoint_ids, + Payload payload, ResultCallback callback) { + assert(payload.GetType() != Payload::Type::kUnknown); + assert(!endpoint_ids.empty()); - service_controller_router_->cancelPayload(client_proxy_.get(), - cancel_payload_params); + router_.SendPayload(&client_, endpoint_ids, std::move(payload), callback); } -template -void Core::disconnectFromEndpoint( - ConstPtr disconnect_from_endpoint_params) { - assert(!disconnect_from_endpoint_params->remote_endpoint_id.empty()); +void Core::CancelPayload(std::int64_t payload_id, ResultCallback callback) { + assert(payload_id != 0); - service_controller_router_->disconnectFromEndpoint( - client_proxy_.get(), disconnect_from_endpoint_params); + router_.CancelPayload(&client_, payload_id, callback); } -template -void Core::stopAllEndpoints( - ConstPtr stop_all_endpoints_params) { - service_controller_router_->stopAllEndpoints(client_proxy_.get(), - stop_all_endpoints_params); +void Core::DisconnectFromEndpoint(absl::string_view endpoint_id, + ResultCallback callback) { + assert(!endpoint_id.empty()); + + router_.DisconnectFromEndpoint(&client_, endpoint_id, callback); +} + +void Core::StopAllEndpoints(ResultCallback callback) { + router_.StopAllEndpoints(&client_, callback); } } // namespace connections diff --git a/cpp/core/core.h b/cpp/core/core.h index 4643dea8..ee6f8486 100644 --- a/cpp/core/core.h +++ b/cpp/core/core.h @@ -1,88 +1,229 @@ #ifndef CORE_CORE_H_ #define CORE_CORE_H_ +#include + #include "core/internal/client_proxy.h" +#include "core/internal/offline_service_controller.h" +#include "core/internal/service_controller.h" #include "core/internal/service_controller_router.h" +#include "core/listeners.h" +#include "core/options.h" #include "core/params.h" -#include "platform/ptr.h" +#include "absl/strings/string_view.h" +#include "absl/types/span.h" namespace location { namespace nearby { namespace connections { -/* - * This class defines the API of the Nearby Connections Core library. - * - * Each passed-in Platform must provide a set of primitives with platform- - * specific implementations. The Platform class must provide factory functions - * for the following primitives: - * - * SingleThreadExecutor - * MultiThreadExecutor - * ScheduledExecutor - * Lock - * CountDownLatch - * AtomicBoolean - * AtomicReference - * SettableFuture - * BluetoothAdapter - * BluetoothClassicMedium - * HashUtils - * ThreadUtils - * SystemClock - * ConditionVariable - * - * A sample Platform definitions can be found at - * //platform/impl/shared/sample/sample_platform.cc - * - * It is no longer necessary to parametrize system types with a platform type. - * New, recommended approach is to define platform support by implementing - * static methods of "location::nearby::platform::ImplementationPlatform" class. - * every library class that needs platform support, must include platform - * header "platform/api/platform.h" and use it. - * To keep textual compatibility, one could define the following alias - * "using Platform = platform::ImplementationPlatform;". - * this will replace the "template " declaration. - * - * As an added benefit, this will allow to not include *.cc files from *.h, - * and let more static analysis happen at compiler stage. - */ -template +// This class defines the API of the Nearby Connections Core library. class Core { public: - Core(); + explicit Core(std::function factory = + []() { return new OfflineServiceController; }) + : router_(factory) {} ~Core(); + Core(Core&&) = default; + Core& operator=(Core&&) = default; - void startAdvertising( - ConstPtr start_advertising_params); - void stopAdvertising(ConstPtr stop_advertising_params); - void startDiscovery(ConstPtr start_discovery_params); - void stopDiscovery(ConstPtr stop_discovery_params); - void requestConnection( - ConstPtr request_connection_params); - void acceptConnection( - ConstPtr accept_connection_params); - void rejectConnection( - ConstPtr reject_connection_params); - void initiateBandwidthUpgrade(ConstPtr - initiate_bandwidth_upgrade_params); - void sendPayload(ConstPtr send_payload_params); - void cancelPayload(ConstPtr cancel_payload_params); - void disconnectFromEndpoint( - ConstPtr disconnect_from_endpoint_params); - void stopAllEndpoints( - ConstPtr stop_all_endpoints_params); + // Starts advertising an endpoint for a local app. + // + // service_id - An identifier to advertise your app to other endpoints. + // This can be an arbitrary string, so long as it uniquely + // identifies your service. A good default is to use your + // app's package name. + // options - The options for advertising. + // info - Connection parameters: + // > name - A human readable name for this endpoint, to appear on + // other devices. + // > listener - A callback notified when remote endpoints request a + // connection to this endpoint. + // callback - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK if advertising started successfully. + // Status::STATUS_ALREADY_ADVERTISING if the app is already advertising. + // Status::STATUS_OUT_OF_ORDER_API_CALL if the app is currently + // connected to remote endpoints; call StopAllEndpoints first. + void StartAdvertising(absl::string_view service_id, ConnectionOptions options, + ConnectionRequestInfo info, ResultCallback callback); + + // Stops advertising a local endpoint. Should be called after calling + // StartAdvertising, as soon as the application no longer needs to advertise + // itself or goes inactive. Payloads can still be sent to connected + // endpoints after advertising ends. + // + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK if none of the above errors occurred. + void StopAdvertising(ResultCallback callback); + + // Starts discovery for remote endpoints with the specified service ID. + // + // service_id - The ID for the service to be discovered, as specified in + // the corresponding call to StartAdvertising. + // listener - A callback notified when a remote endpoint is discovered. + // options - The options for discovery. + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK if discovery started successfully. + // Status::STATUS_ALREADY_DISCOVERING if the app is already + // discovering the specified service. + // Status::STATUS_OUT_OF_ORDER_API_CALL if the app is currently + // connected to remote endpoints; call StopAllEndpoints first. + void StartDiscovery(absl::string_view service_id, ConnectionOptions options, + DiscoveryListener listener, ResultCallback callback); + + // Stops discovery for remote endpoints, after a previous call to + // StartDiscovery, when the client no longer needs to discover endpoints or + // goes inactive. Payloads can still be sent to connected endpoints after + // discovery ends. + // + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK if none of the above errors occurred. + void StopDiscovery(ResultCallback callback); + + // Invokes the discovery callback from a previous call to StartDiscovery() + // with the given endpoint info. The previous call to StartDiscovery() must + // have been passed ConnectionOptions with is_out_of_band_connection == true. + // + // service_id - The ID for the service to be discovered, as + // specified in the corresponding call to + // StartDiscovery(). + // metadata - Metadata used in order to inject the endpoint. + // result_cb - to access the status of the operation when + // available. + // Possible status codes include: + // Status::kSuccess if endpoint injection was attempted. + // Status::kError if bluetooth_mac_address is malformed. + // Status::kOutOfOrderApiCall if the app is not discovering. + void InjectEndpoint(absl::string_view service_id, + OutOfBandConnectionMetadata metadata, + ResultCallback callback); + + // Sends a request to connect to a remote endpoint. + // + // endpoint_id - The identifier for the remote endpoint to which a + // connection request will be sent. Should match the value + // provided in a call to + // DiscoveryListener::endpoint_found_cb() + // info - Connection parameters: + // > name - A human readable name for the local endpoint, to appear on + // the remote endpoint. + // > listener - A callback notified when the remote endpoint sends a + // response to the connection request. + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK if the connection request was sent. + // Status::STATUS_ALREADY_CONNECTED_TO_ENDPOINT if the app already + // has a connection to the specified endpoint. + // Status::STATUS_RADIO_ERROR if we failed to connect because of an + // issue with Bluetooth/WiFi. + // Status::STATUS_ERROR if we failed to connect for any other reason. + void RequestConnection(absl::string_view endpoint_id, + ConnectionRequestInfo info, ConnectionOptions options, + ResultCallback callback); + + // Accepts a connection to a remote endpoint. This method must be called + // before Payloads can be exchanged with the remote endpoint. + // + // endpoint_id - The identifier for the remote endpoint. Should match the + // value provided in a call to + // ConnectionListener::onConnectionInitiated. + // listener - A callback for payloads exchanged with the remote endpoint. + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK if the connection request was accepted. + // Status::STATUS_ALREADY_CONNECTED_TO_ENDPOINT if the app already. + // has a connection to the specified endpoint. + void AcceptConnection(absl::string_view endpoint_id, PayloadListener listener, + ResultCallback callback); + + // Rejects a connection to a remote endpoint. + // + // endpoint_id - The identifier for the remote endpoint. Should match the + // value provided in a call to + // ConnectionListener::onConnectionInitiated(). + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK} if the connection request was rejected. + // Status::STATUS_ALREADY_CONNECTED_TO_ENDPOINT} if the app already + // has a connection to the specified endpoint. + void RejectConnection(absl::string_view endpoint_id, ResultCallback callback); + + // Sends a Payload to a remote endpoint. Payloads can only be sent to remote + // endpoints once a notice of connection acceptance has been delivered via + // ConnectionListener::onConnectionResult(). + // + // endpoint_ids - Array of remote endpoint identifiers for the to which the + // payload should be sent. + // payload - The Payload to be sent. + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OUT_OF_ORDER_API_CALL if the device has not first + // performed advertisement or discovery (to set the Strategy. + // Status::STATUS_ENDPOINT_UNKNOWN if there's no active (or pending) + // connection to the remote endpoint. + // Status::STATUS_OK if none of the above errors occurred. Note that this + // indicates that Nearby Connections will attempt to send the Payload, + // but not that the send has successfully completed yet. Errors might + // still occur during transmission (and at different times for + // different endpoints), and will be delivered via + // PayloadCallback#onPayloadTransferUpdate. + void SendPayload(absl::Span endpoint_ids, Payload payload, + ResultCallback callback); + + // Cancels a Payload currently in-flight to or from remote endpoint(s). + // + // payload_id - The identifier for the Payload to be canceled. + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK if none of the above errors occurred. + void CancelPayload(std::int64_t payload_id, ResultCallback callback); + + // Disconnects from a remote endpoint. {@link Payload}s can no longer be sent + // to or received from the endpoint after this method is called. + // + // endpoint_id - The identifier for the remote endpoint to disconnect from. + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK - finished successfully. + void DisconnectFromEndpoint(absl::string_view endpoint_id, + ResultCallback callback); + + // Disconnects from, and removes all traces of, all connected and/or + // discovered endpoints. This call is expected to be preceded by a call to + // StopAdvertising or StartDiscovery as needed. After calling + // StopAllEndpoints, no further operations with remote endpoints will be + // possible until a new call to one of StartAdvertising() or StartDiscovery(). + // + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK - finished successfully. + void StopAllEndpoints(ResultCallback callback); + + // Sends a request to initiate connection bandwidth upgrade. + // + // endpoint_id - The identifier for the remote endpoint which will be + // switching to a higher connection data rate and possibly + // different wireless protocol. On success, calls + // ConnectionListener::bandwidth_changed_cb(). + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK - finished successfully. + void InitiateBandwidthUpgrade(absl::string_view endpoint_id, + ResultCallback callback); private: - ScopedPtr > > client_proxy_; - ScopedPtr > > - service_controller_router_; + static constexpr absl::Duration kWaitForDisconnect = absl::Milliseconds(5000); + + ClientProxy client_; + ServiceControllerRouter router_; }; } // namespace connections } // namespace nearby } // namespace location -#include "core/core.cc" - #endif // CORE_CORE_H_ diff --git a/cpp/core_v2/core_test.cc b/cpp/core/core_test.cc similarity index 84% rename from cpp/core_v2/core_test.cc rename to cpp/core/core_test.cc index 038383e3..ac9351e7 100644 --- a/cpp/core_v2/core_test.cc +++ b/cpp/core/core_test.cc @@ -1,9 +1,9 @@ -#include "core_v2/core.h" +#include "core/core.h" -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/mock_service_controller.h" -#include "core_v2/internal/service_controller.h" -#include "platform_v2/public/logging.h" +#include "core/internal/client_proxy.h" +#include "core/internal/mock_service_controller.h" +#include "core/internal/service_controller.h" +#include "platform/public/logging.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/time/clock.h" diff --git a/cpp/core/internal/BUILD b/cpp/core/internal/BUILD index 9c7f303b..6baa01da 100644 --- a/cpp/core/internal/BUILD +++ b/cpp/core/internal/BUILD @@ -1,89 +1,94 @@ cc_library( name = "internal", srcs = [ - "bandwidth_upgrade_manager.cc", - "base_bandwidth_upgrade_handler.cc", "base_endpoint_channel.cc", + "base_pcp_handler.cc", "ble_advertisement.cc", "ble_endpoint_channel.cc", "bluetooth_device_name.cc", "bluetooth_endpoint_channel.cc", + "bwu_manager.cc", + "client_proxy.cc", + "encryption_runner.cc", "endpoint_channel_manager.cc", + "endpoint_manager.cc", "internal_payload.cc", - "internal_payload.h", - "loop_runner.cc", - "loop_runner.h", + "internal_payload_factory.cc", "offline_frames.cc", + "offline_service_controller.cc", + "p2p_cluster_pcp_handler.cc", + "p2p_point_to_point_pcp_handler.cc", + "p2p_star_pcp_handler.cc", + "payload_manager.cc", + "pcp_manager.cc", + "service_controller_router.cc", + "webrtc_bwu_handler.cc", + "webrtc_endpoint_channel.cc", "wifi_lan_endpoint_channel.cc", "wifi_lan_service_info.cc", ], hdrs = [ - "bandwidth_upgrade_handler.h", - "bandwidth_upgrade_manager.h", - "base_bandwidth_upgrade_handler.h", + "base_bwu_handler.h", "base_endpoint_channel.h", - "base_pcp_handler.cc", "base_pcp_handler.h", "ble_advertisement.h", - "ble_compat.h", "ble_endpoint_channel.h", "bluetooth_device_name.h", "bluetooth_endpoint_channel.h", - "client_proxy.cc", + "bwu_handler.h", + "bwu_manager.h", "client_proxy.h", - "encryption_runner.cc", "encryption_runner.h", "endpoint_channel.h", "endpoint_channel_manager.h", - "endpoint_manager.cc", "endpoint_manager.h", - "internal_payload_factory.cc", + "internal_payload.h", "internal_payload_factory.h", - "medium_manager.cc", - "medium_manager.h", "offline_frames.h", - "offline_service_controller.cc", "offline_service_controller.h", - "p2p_cluster_pcp_handler.cc", "p2p_cluster_pcp_handler.h", - "p2p_point_to_point_pcp_handler.cc", "p2p_point_to_point_pcp_handler.h", - "p2p_star_pcp_handler.cc", "p2p_star_pcp_handler.h", - "payload_manager.cc", "payload_manager.h", "pcp.h", "pcp_handler.h", - "pcp_manager.cc", "pcp_manager.h", "service_controller.h", - "service_controller_router.cc", "service_controller_router.h", + "webrtc_bwu_handler.h", + "webrtc_endpoint_channel.h", "wifi_lan_endpoint_channel.h", "wifi_lan_service_info.h", - "wifi_lan_upgrade_handler.cc", - "wifi_lan_upgrade_handler.h", ], visibility = [ "//core:__pkg__", ], deps = [ - "//core:types", + "//core:core_types", + "//core/internal:message_lite", "//core/internal/mediums", + "//core/internal/mediums:utils", + "//core/internal/mediums/webrtc", "//proto/connections:offline_wire_formats_portable_proto", - "//platform:logging", - "//platform:types", - "//platform:utils", - "//platform/api", - "//platform/port:string", + "//platform/base", + "//platform/base:util", + "//platform/public:comm", + "//platform/public:logging", + "//platform/public:types", "//proto:connections_enums_portable_proto", - "//net/proto2/compat/public:proto2_lite", "//securegcm:ukey2", + "//absl/base:core_headers", + "//absl/container:btree", + "//absl/container:flat_hash_map", + "//absl/container:flat_hash_set", + "//absl/functional:bind_front", + "//absl/memory", "//absl/strings", + "//absl/time", + "//absl/types:span", ], ) -# TODO(apolyudov): remove when api v2 rework is done. cc_library( name = "message_lite", hdrs = [ @@ -91,75 +96,82 @@ cc_library( ], visibility = [ "//core:__subpackages__", - "//core_v2:__subpackages__", ], deps = [ "//net/proto2/compat/public:proto2_lite", ], ) -cc_test( - name = "base_endpoint_channel_test", - srcs = ["base_endpoint_channel_test.cc"], - deps = [ - ":internal", - "//platform:utils", - "//platform/api", - "//platform/impl/g3", - "//proto:connections_enums_portable_proto", - "//testing/base/public:gunit_main", - ], -) - -cc_test( - name = "bluetooth_device_name_test", - srcs = ["bluetooth_device_name_test.cc"], - deps = [ - ":internal", - "//platform:utils", - "//platform/api", - "//platform/impl/g3", - "//platform/port:string", - "//testing/base/public:gunit_main", - ], -) - -cc_test( - name = "ble_advertisement_test", - srcs = ["ble_advertisement_test.cc"], - deps = [ - ":internal", - "//platform/api", - "//platform/impl/g3", - "//platform/port:string", - "//testing/base/public:gunit_main", - ], -) - -cc_test( - name = "wifi_lan_service_info_test", - srcs = ["wifi_lan_service_info_test.cc"], - deps = [ - ":internal", - "//platform:utils", - "//platform/api", - "//platform/impl/g3", - "//platform/port:string", - "//testing/base/public:gunit_main", - ], -) - -cc_test( - name = "offline_frames_test", +cc_library( + name = "internal_test", + testonly = True, srcs = [ - "offline_frames_test.cc", + "offline_simulation_user.cc", + "simulation_user.cc", + ], + hdrs = [ + "mock_service_controller.h", + "offline_simulation_user.h", + "simulation_user.h", + ], + visibility = [ + "//core:__subpackages__", ], deps = [ ":internal", + "//core:core_types", + "//platform/base", + "//platform/base:test_util", + "//platform/public:types", + "//testing/base/public:gunit", + "//absl/functional:bind_front", + "//absl/strings", + ], +) + +cc_test( + name = "core_internal_test", + size = "small", + timeout = "moderate", + srcs = [ + "base_endpoint_channel_test.cc", + "base_pcp_handler_test.cc", + "ble_advertisement_test.cc", + "bluetooth_device_name_test.cc", + "bwu_manager_test.cc", + "client_proxy_test.cc", + "encryption_runner_test.cc", + "endpoint_channel_manager_test.cc", + "endpoint_manager_test.cc", + "internal_payload_factory_test.cc", + "offline_frames_test.cc", + "offline_service_controller_test.cc", + "p2p_cluster_pcp_handler_test.cc", + "payload_manager_test.cc", + "pcp_manager_test.cc", + "service_controller_router_test.cc", + "wifi_lan_service_info_test.cc", + ], + shard_count = 16, + deps = [ + ":internal", + ":internal_test", + "//core:core_types", + "//core/internal/mediums", "//proto/connections:offline_wire_formats_portable_proto", - "//platform:types", - "//platform/api", - "//platform/impl/g3", + "//platform/base", + "//platform/base:test_util", + "//platform/impl/g3", # build_cleaner: keep + "//platform/public:logging", + "//platform/public:types", + "//proto:connections_enums_portable_proto", + "//securegcm:ukey2", + "//testing/base/public:gunit", "//testing/base/public:gunit_main", + "//absl/container:flat_hash_set", + "//absl/strings", + "//absl/synchronization", + "//absl/time", + "//absl/types:span", ], ) diff --git a/cpp/core/internal/bandwidth_upgrade_handler.h b/cpp/core/internal/bandwidth_upgrade_handler.h deleted file mode 100644 index 2ce07b7a..00000000 --- a/cpp/core/internal/bandwidth_upgrade_handler.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef CORE_INTERNAL_BANDWIDTH_UPGRADE_HANDLER_H_ -#define CORE_INTERNAL_BANDWIDTH_UPGRADE_HANDLER_H_ - -#include "core/internal/client_proxy.h" -#include "proto/connections/offline_wire_formats.pb.h" -#include "platform/api/count_down_latch.h" -#include "platform/api/platform.h" -#include "platform/port/string.h" -#include "proto/connections_enums.pb.h" - -namespace location { -namespace nearby { -namespace connections { - -// Defines the set of methods that need to be implemented to handle the -// per-Medium-specific operations needed to upgrade an EndpointChannel. -class BandwidthUpgradeHandler { - public: - using Platform = platform::ImplementationPlatform; - - virtual ~BandwidthUpgradeHandler() {} - - // Reverts any changes made to the device in the process of upgrading - // endpoints. - virtual void revert() = 0; - - // Cleans up in-progress upgrades after endpoint disconnection. - virtual void processEndpointDisconnection( - Ptr > client_proxy, const std::string& endpoint_id, - Ptr process_disconnection_barrier) = 0; - - // Initiates the upgrade for the endpoint and starts listening for upgraded - // incoming connections on the initiator side of the bandwidth upgrade. - virtual void initiateBandwidthUpgradeForEndpoint( - Ptr > client_proxy, - const std::string& endpoint_id) = 0; - - // Processes the BandwidthUpgradeNegotiationFrames that come over the - // EndpointChannel on the non-initiator side of the bandwidth upgrade. - // TODO(ahlee): Rename parameters in the java code. - virtual void processBandwidthUpgradeNegotiationFrame( - ConstPtr bandwidth_upgrade_negotiation, - Ptr > to_client_proxy, - const std::string& from_endpoint_id, - proto::connections::Medium current_medium) = 0; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_INTERNAL_BANDWIDTH_UPGRADE_HANDLER_H_ diff --git a/cpp/core/internal/bandwidth_upgrade_manager.cc b/cpp/core/internal/bandwidth_upgrade_manager.cc deleted file mode 100644 index 4eabbabe..00000000 --- a/cpp/core/internal/bandwidth_upgrade_manager.cc +++ /dev/null @@ -1,41 +0,0 @@ -#include "core/internal/bandwidth_upgrade_manager.h" - -#include "proto/connections_enums.pb.h" - -namespace location { -namespace nearby { -namespace connections { - -BandwidthUpgradeManager::BandwidthUpgradeManager( - Ptr > medium_manager, - Ptr endpoint_channel_manager, - Ptr > endpoint_manager) - : endpoint_manager_(endpoint_manager), - bandwidth_upgrade_handlers_(), - current_bandwidth_upgrade_handler_() {} - -BandwidthUpgradeManager::~BandwidthUpgradeManager() { - // TODO(ahlee): Make sure we don't repeat the mistake fixed in cl/201883908. -} - -void BandwidthUpgradeManager::initiateBandwidthUpgradeForEndpoint( - Ptr > client_proxy, const string& endpoint_id, - proto::connections::Medium medium) {} - -void BandwidthUpgradeManager::processIncomingOfflineFrame( - ConstPtr offline_frame, const string& from_endpoint_id, - Ptr > to_client_proxy, - proto::connections::Medium current_medium) {} - -void BandwidthUpgradeManager::processEndpointDisconnection( - Ptr > client_proxy, const string& endpoint_id, - Ptr process_disconnection_barrier) {} - -bool BandwidthUpgradeManager::setCurrentBandwidthUpgradeHandler( - proto::connections::Medium medium) { - return false; -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core/internal/bandwidth_upgrade_manager.h b/cpp/core/internal/bandwidth_upgrade_manager.h deleted file mode 100644 index da7a3e8f..00000000 --- a/cpp/core/internal/bandwidth_upgrade_manager.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef CORE_INTERNAL_BANDWIDTH_UPGRADE_MANAGER_H_ -#define CORE_INTERNAL_BANDWIDTH_UPGRADE_MANAGER_H_ - -#include - -#include "core/internal/bandwidth_upgrade_handler.h" -#include "core/internal/client_proxy.h" -#include "core/internal/endpoint_channel_manager.h" -#include "core/internal/endpoint_manager.h" -#include "core/internal/medium_manager.h" -#include "proto/connections/offline_wire_formats.pb.h" -#include "platform/api/platform.h" -#include "platform/port/string.h" -#include "platform/ptr.h" -#include "proto/connections_enums.pb.h" - -namespace location { -namespace nearby { -namespace connections { - -// Manages all known {@link BandwidthUpgradeHandler} implementations, delegating -// operations to the appropriate one as per the parameters passed in. -class BandwidthUpgradeManager - : public EndpointManager< - platform::ImplementationPlatform>::IncomingOfflineFrameProcessor { - public: - using Platform = platform::ImplementationPlatform; - - BandwidthUpgradeManager(Ptr> medium_manager, - Ptr endpoint_channel_manager, - Ptr> endpoint_manager); - ~BandwidthUpgradeManager() override; - - // This is the point on the initiator side where the - // current_bandwidth_upgrade_handler_ is set. - void initiateBandwidthUpgradeForEndpoint( - Ptr > client_proxy, const string& endpoint_id, - proto::connections::Medium medium); - // This is the point on the non-initiator side where the - // current_bandwidth_upgrade_handler_ is set. - // @EndpointManagerReaderThread - void processIncomingOfflineFrame( - ConstPtr offline_frame, const string& from_endpoint_id, - Ptr > to_client_proxy, - proto::connections::Medium current_medium) override; - // @EndpointManagerReaderThread - void processEndpointDisconnection( - Ptr > client_proxy, const string& endpoint_id, - Ptr process_disconnection_barrier) override; - - private: - bool setCurrentBandwidthUpgradeHandler(proto::connections::Medium medium); - - Ptr > endpoint_manager_; - typedef std::map> - BandwidthUpgradeHandlersMap; - BandwidthUpgradeHandlersMap bandwidth_upgrade_handlers_; - Ptr current_bandwidth_upgrade_handler_; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_INTERNAL_BANDWIDTH_UPGRADE_MANAGER_H_ diff --git a/cpp/core/internal/base_bandwidth_upgrade_handler.cc b/cpp/core/internal/base_bandwidth_upgrade_handler.cc deleted file mode 100644 index e58c6301..00000000 --- a/cpp/core/internal/base_bandwidth_upgrade_handler.cc +++ /dev/null @@ -1,122 +0,0 @@ -#include "core/internal/base_bandwidth_upgrade_handler.h" - -namespace location { -namespace nearby { -namespace connections { - -namespace { -using Platform = platform::ImplementationPlatform; -} - -namespace base_bandwidth_upgrade_handler { - -class RevertRunnable : public Runnable { - public: - void run() override {} -}; - -class InitiateBandwidthUpgradeForEndpointRunnable : public Runnable { - public: - void run() override {} -}; - -class ProcessEndpointDisconnectionRunnable : public Runnable { - public: - void run() override {} -}; - -class ProcessBandwidthUpgradeNegotiationFrameRunnable : public Runnable { - public: - void run() override {} -}; - -} // namespace base_bandwidth_upgrade_handler - -BaseBandwidthUpgradeHandler::BaseBandwidthUpgradeHandler( - Ptr endpoint_channel_manager) - : endpoint_channel_manager_(endpoint_channel_manager), - alarm_executor_(nullptr), - serial_executor_(nullptr), - previous_endpoint_channels_(), - in_progress_upgrades_(), - safe_to_close_write_timestamps_() {} - -BaseBandwidthUpgradeHandler::~BaseBandwidthUpgradeHandler() {} - -void BaseBandwidthUpgradeHandler::revert() {} - -void BaseBandwidthUpgradeHandler::processEndpointDisconnection( - Ptr > client_proxy, const string& endpoint_id, - Ptr process_disconnection_barrier) {} - -void BaseBandwidthUpgradeHandler::initiateBandwidthUpgradeForEndpoint( - Ptr > client_proxy, const string& endpoint_id) {} - -void BaseBandwidthUpgradeHandler::processBandwidthUpgradeNegotiationFrame( - ConstPtr bandwidth_upgrade_negotiation, - Ptr > to_client_proxy, const string& from_endpoint_id, - proto::connections::Medium current_medium) {} - -Ptr -BaseBandwidthUpgradeHandler::getEndpointChannelManager() { - return endpoint_channel_manager_; -} - -void BaseBandwidthUpgradeHandler::onIncomingConnection( - Ptr incoming_socket_connection) {} - -void BaseBandwidthUpgradeHandler::runOnBandwidthUpgradeHandlerThread( - Ptr runnable) {} - -void BaseBandwidthUpgradeHandler::runUpgradeProtocol( - Ptr > client_proxy, const string& endpoint_id, - Ptr new_endpoint_channel) {} - -void BaseBandwidthUpgradeHandler::processBandwidthUpgradePathAvailableEvent( - const string& endpoint_id, Ptr > client_proxy, - ConstPtr - upgrade_path_info, - proto::connections::Medium current_medium) {} - -Ptr -BaseBandwidthUpgradeHandler::processBandwidthUpgradePathAvailableEventInternal( - const string& endpoint_id, Ptr > client_proxy, - ConstPtr - upgrade_path_info) { - return Ptr(); -} - -void BaseBandwidthUpgradeHandler::processLastWriteToPriorChannelEvent( - Ptr > client_proxy, const string& endpoint_id) {} - -void BaseBandwidthUpgradeHandler::processSafeToClosePriorChannelEvent( - Ptr > client_proxy, const string& endpoint_id) {} - -std::int64_t BaseBandwidthUpgradeHandler::calculateCloseDelay( - const string& endpoint_id) { - return 0; -} - -std::int64_t BaseBandwidthUpgradeHandler::getMillisSinceSafeCloseWritten( - const string& endpoint_id) { - return 0; -} - -// TODO(ahlee): This will differ from the Java code as we don't have to handle -// analytics in the C++ code. -void BaseBandwidthUpgradeHandler:: - attemptToRecordBandwidthUpgradeErrorForUnknownEndpoint( - proto::connections::BandwidthUpgradeResult result, - proto::connections::BandwidthUpgradeErrorStage error_stage) {} - -// TODO(ahlee): This will differ from the Java code (previously threw an -// UpgradeException). -Ptr -BaseBandwidthUpgradeHandler::readClientIntroductionFrame( - Ptr endpoint_channel) { - return Ptr(); -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core/internal/base_bandwidth_upgrade_handler.h b/cpp/core/internal/base_bandwidth_upgrade_handler.h deleted file mode 100644 index 78320abe..00000000 --- a/cpp/core/internal/base_bandwidth_upgrade_handler.h +++ /dev/null @@ -1,181 +0,0 @@ -#ifndef CORE_INTERNAL_BASE_BANDWIDTH_UPGRADE_HANDLER_H_ -#define CORE_INTERNAL_BASE_BANDWIDTH_UPGRADE_HANDLER_H_ - -#include -#include - -#include "core/internal/bandwidth_upgrade_handler.h" -#include "core/internal/client_proxy.h" -#include "core/internal/endpoint_channel_manager.h" -#include "proto/connections/offline_wire_formats.pb.h" -#include "platform/api/count_down_latch.h" -#include "platform/port/string.h" -#include "platform/ptr.h" -#include "proto/connections_enums.pb.h" - -namespace location { -namespace nearby { -namespace connections { - -namespace base_bandwidth_upgrade_handler { - -class RevertRunnable; -class InitiateBandwidthUpgradeForEndpointRunnable; -class ProcessEndpointDisconnectionRunnable; -class ProcessBandwidthUpgradeNegotiationFrameRunnable; - -} // namespace base_bandwidth_upgrade_handler - -// Base class for managing the upgrade of endpoints to a different medium for -// communication (from whatever they were previously using). -// -//

The sequencing of the upgrade protocol is as follows: -//

    -//
  • Initiator sets up an upgrade path, sends -// BANDWIDTH_UPGRADE_NEGOTIATION.UPGRADE_PATH_AVAILABLE to Responder over -// the prior EndpointChannel. -//
  • Responder joins the upgrade path, sends (without encryption) -// BANDWIDTH_UPGRADE_NEGOTIATION.CLIENT_INTRODUCTION over the new -// EndpointChannel, and sends -// BANDWIDTH_UPGRADE_NEGOTIATION.LAST_WRITE_TO_PRIOR_CHANNEL over the -// prior EndpointChannel. -//
  • Initiator receives BANDWIDTH_UPGRADE_NEGOTIATION.CLIENT_INTRODUCTION -// over the newly-established EndpointChannel, and sends -// BANDWIDTH_UPGRADE_NEGOTIATION.LAST_WRITE_TO_PRIOR_CHANNEL over the -// prior EndpointChannel. -//
  • Both wait to receive -// BANDWIDTH_UPGRADE_NEGOTIATION.LAST_WRITE_TO_PRIOR_CHANNEL from the -// other, and upon doing so, send -// BANDWIDTH_UPGRADE_NEGOTIATION.SAFE_TO_CLOSE_PRIOR_CHANNEL to each other -//
  • Both then wait to receive -// BANDWIDTH_UPGRADE_NEGOTIATION.SAFE_TO_CLOSE_PRIOR_CHANNEL from the -// other, and upon doing so, close the prior EndpointChannel. -//
-class BaseBandwidthUpgradeHandler : public BandwidthUpgradeHandler { - public: - using Platform = platform::ImplementationPlatform; - - explicit BaseBandwidthUpgradeHandler( - Ptr endpoint_channel_manager); - ~BaseBandwidthUpgradeHandler() override; - - void revert() override; - void processEndpointDisconnection( - Ptr > client_proxy, const string& endpoint_id, - Ptr process_disconnection_barrier) override; - // Initiates the bandwidth upgrade and sends an UPGRADE_PATH_AVAILABLE - // OfflineFrame. - void initiateBandwidthUpgradeForEndpoint( - Ptr > client_proxy, - const string& endpoint_id) override; - void processBandwidthUpgradeNegotiationFrame( - ConstPtr bandwidth_upgrade_negotiation, - Ptr > to_client_proxy, - const string& from_endpoint_id, - proto::connections::Medium current_medium) override; - - protected: - // Represents the incoming Socket the Initiator has gotten after initializing - // its upgraded bandwidth medium. - class IncomingSocketConnection { - public: - virtual ~IncomingSocketConnection() {} - - virtual string socketToString() = 0; - virtual void closeSocket() = 0; - // TODO(ahlee): Make sure to be careful with the ownership story of this. - // Leaning towards releasing to the caller. - virtual Ptr getEndpointChannel() = 0; - }; - - // Called by the Initiator to setup the upgraded medium for this endpoint (if - // that hasn't already been done), and returns a serialized UpgradePathInfo - // that can be sent to the Responder. - // TODO(ahlee): This will differ from the Java code (previously threw an - // UpgradeException). Leaving the return type simple for the skeleton - I'll - // switch to a pair if the result enum is needed. - // @BandwidthUpgradeHandlerThread - virtual ConstPtr initializeUpgradedMediumForEndpoint( - const string& endpoint_id) = 0; - // Called to revert any state changed by the Initiator to setup the upgraded - // medium for an endpoint. - // @BandwidthUpgradeHandlerThread - virtual void revertImpl() = 0; - // Called by the Responder to setup the upgraded medium for this endpoint (if - // that hasn't already been done) using the UpgradePathInfo sent by the - // Initiator, and returns a new EndpointChannel for the upgraded medium. - // @BandwidthUpgradeHandlerThread - // TODO(ahlee): This will differ from the Java code (previously threw an - // exception). - virtual Ptr createUpgradedEndpointChannel( - const string& endpoint_id, - ConstPtr - upgrade_path_info) = 0; - // Returns the upgrade medium of the BandwidthUpgradeHandler. - // @BandwidthUpgradeHandlerThread - virtual proto::connections::Medium getUpgradeMedium() = 0; - - Ptr getEndpointChannelManager(); - // Common functionality to take an incoming connection and go through the - // upgrade process. - // @BandwidthUpgradeHandlerThread - void onIncomingConnection( - Ptr incoming_socket_connection); - void runOnBandwidthUpgradeHandlerThread(Ptr runnable); - - private: - friend class base_bandwidth_upgrade_handler::RevertRunnable; - friend class base_bandwidth_upgrade_handler:: - InitiateBandwidthUpgradeForEndpointRunnable; - friend class base_bandwidth_upgrade_handler:: - ProcessEndpointDisconnectionRunnable; - friend class base_bandwidth_upgrade_handler:: - ProcessBandwidthUpgradeNegotiationFrameRunnable; - - void runUpgradeProtocol(Ptr > client_proxy, - const string& endpoint_id, - Ptr new_endpoint_channel); - void processBandwidthUpgradePathAvailableEvent( - const string& endpoint_id, Ptr > client_proxy, - ConstPtr - upgrade_path_info, - proto::connections::Medium current_medium); - Ptr processBandwidthUpgradePathAvailableEventInternal( - const string& endpoint_id, Ptr > client_proxy, - ConstPtr - upgrade_path_info); - void processLastWriteToPriorChannelEvent( - Ptr > client_proxy, const string& endpoint_id); - void processSafeToClosePriorChannelEvent( - Ptr > client_proxy, const string& endpoint_id); - std::int64_t calculateCloseDelay(const string& endpoint_id); - std::int64_t getMillisSinceSafeCloseWritten(const string& endpoint_id); - void attemptToRecordBandwidthUpgradeErrorForUnknownEndpoint( - proto::connections::BandwidthUpgradeResult result, - proto::connections::BandwidthUpgradeErrorStage error_stage); - Ptr - readClientIntroductionFrame(Ptr endpoint_channel); - - Ptr endpoint_channel_manager_; - ScopedPtr > alarm_executor_; - ScopedPtr > serial_executor_; - // Stores each upgraded endpoint's previous EndpointChannel (that was - // displaced in favor of a new EndpointChannel) temporarily, until it can - // safely be shut down for good in processLastWriteToPriorChannelEvent(). - typedef std::map > PreviousEndpointChannelsMap; - PreviousEndpointChannelsMap previous_endpoint_channels_; - // Maps endpointId -> ClientProxy for which - // initiateBandwidthUpgradeForEndpoint() has been called but which have not - // yet completed the upgrade via onIncomingConnection(). - typedef std::map > > InProgressUpgradesMap; - InProgressUpgradesMap in_progress_upgrades_; - // Maps endpointId -> timestamp of when the SAFE_TO_CLOSE message was written. - typedef std::map SafeToCloseWriteTimestampsMap; - SafeToCloseWriteTimestampsMap safe_to_close_write_timestamps_; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_INTERNAL_BASE_BANDWIDTH_UPGRADE_HANDLER_H_ diff --git a/cpp/core_v2/internal/base_bwu_handler.h b/cpp/core/internal/base_bwu_handler.h similarity index 70% rename from cpp/core_v2/internal/base_bwu_handler.h rename to cpp/core/internal/base_bwu_handler.h index 23b0abd0..33703d46 100644 --- a/cpp/core_v2/internal/base_bwu_handler.h +++ b/cpp/core/internal/base_bwu_handler.h @@ -1,18 +1,18 @@ -#ifndef CORE_V2_INTERNAL_BASE_BWU_HANDLER_H_ -#define CORE_V2_INTERNAL_BASE_BWU_HANDLER_H_ +#ifndef CORE_INTERNAL_BASE_BWU_HANDLER_H_ +#define CORE_INTERNAL_BASE_BWU_HANDLER_H_ #include #include #include -#include "core_v2/internal/bwu_handler.h" -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/endpoint_channel_manager.h" +#include "core/internal/bwu_handler.h" +#include "core/internal/client_proxy.h" +#include "core/internal/endpoint_channel_manager.h" #include "proto/connections/offline_wire_formats.pb.h" -#include "platform_v2/public/cancelable_alarm.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/scheduled_executor.h" -#include "platform_v2/public/single_thread_executor.h" +#include "platform/public/cancelable_alarm.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/scheduled_executor.h" +#include "platform/public/single_thread_executor.h" #include "proto/connections_enums.pb.h" #include "absl/container/flat_hash_map.h" #include "absl/time/clock.h" @@ -45,4 +45,4 @@ class BaseBwuHandler : public BwuHandler { } // namespace nearby } // namespace location -#endif // CORE_V2_INTERNAL_BASE_BWU_HANDLER_H_ +#endif // CORE_INTERNAL_BASE_BWU_HANDLER_H_ diff --git a/cpp/core/internal/base_endpoint_channel.cc b/cpp/core/internal/base_endpoint_channel.cc index 8df7d4bc..beffa04a 100644 --- a/cpp/core/internal/base_endpoint_channel.cc +++ b/cpp/core/internal/base_endpoint_channel.cc @@ -2,9 +2,15 @@ #include -#include "platform/api/platform.h" -#include "platform/synchronized.h" +#include "core/internal/offline_frames.h" +#include "platform/base/byte_array.h" +#include "platform/base/exception.h" +#include "platform/public/logging.h" +#include "platform/public/mutex.h" +#include "platform/public/mutex_lock.h" #include "proto/connections_enums.pb.h" +#include "absl/strings/escaping.h" +#include "absl/strings/str_cat.h" namespace location { namespace nearby { @@ -12,10 +18,8 @@ namespace connections { namespace { -using Platform = platform::ImplementationPlatform; - -std::int32_t bytesToInt(ConstPtr bytes) { - const char* int_bytes = bytes->getData(); +std::int32_t BytesToInt(const ByteArray& bytes) { + const char* int_bytes = bytes.data(); std::int32_t result = 0; result |= (static_cast(int_bytes[0]) & 0x0FF) << 24; @@ -26,308 +30,264 @@ std::int32_t bytesToInt(ConstPtr bytes) { return result; } -ConstPtr intToBytes(std::int32_t value) { +ByteArray IntToBytes(std::int32_t value) { char int_bytes[sizeof(std::int32_t)]; int_bytes[0] = static_cast((value >> 24) & 0x0FF); int_bytes[1] = static_cast((value >> 16) & 0x0FF); int_bytes[2] = static_cast((value >> 8) & 0x0FF); int_bytes[3] = static_cast((value)&0x0FF); - return MakeConstPtr(new ByteArray(int_bytes, sizeof(int_bytes))); + return ByteArray(int_bytes, sizeof(int_bytes)); } -ExceptionOr> readExactly(Ptr reader, - std::int64_t size) { - string buffer; - std::int64_t remaining_size = size; +ExceptionOr ReadExactly(InputStream* reader, std::int64_t size) { + ByteArray buffer(size); + std::int64_t current_pos = 0; - while (remaining_size > 0) { - ExceptionOr> read_bytes = reader->read(remaining_size); + while (current_pos < size) { + ExceptionOr read_bytes = reader->Read(size - current_pos); if (!read_bytes.ok()) { - if (Exception::IO == read_bytes.exception()) { - return ExceptionOr>(read_bytes.exception()); - } + return read_bytes; } - // Avoid leaks. - ScopedPtr> scoped_read_bytes(read_bytes.result()); + ByteArray result = read_bytes.result(); - // In Java, EOFException is a sub-variant of IOException. - if (scoped_read_bytes.isNull() || scoped_read_bytes->size() == 0) { - return ExceptionOr>(Exception::IO); + if (result.Empty()) { + return ExceptionOr(Exception::kIo); } - buffer.append(scoped_read_bytes->getData(), scoped_read_bytes->size()); - remaining_size -= scoped_read_bytes->size(); + buffer.CopyAt(current_pos, result); + current_pos += result.size(); } - return ExceptionOr>( - MakeConstPtr(new ByteArray(buffer.data(), buffer.size()))); + return ExceptionOr(std::move(buffer)); } -ExceptionOr readInt(Ptr reader) { - ExceptionOr> read_bytes = - readExactly(reader, sizeof(std::int32_t)); +ExceptionOr ReadInt(InputStream* reader) { + ExceptionOr read_bytes = ReadExactly(reader, sizeof(std::int32_t)); if (!read_bytes.ok()) { - if (Exception::IO == read_bytes.exception()) { - return ExceptionOr(read_bytes.exception()); - } + return ExceptionOr(read_bytes.exception()); } - // Avoid leaks. - ScopedPtr> scoped_read_bytes(read_bytes.result()); - - return ExceptionOr(bytesToInt(scoped_read_bytes.get())); + return ExceptionOr(BytesToInt(std::move(read_bytes.result()))); } -Exception::Value writeInt(Ptr writer, std::int32_t value) { - return writer->write(intToBytes(value)); +Exception WriteInt(OutputStream* writer, std::int32_t value) { + return writer->Write(IntToBytes(value)); } } // namespace -// TODO(b/150763574): Move implementatiopn to header or .inc file. -BaseEndpointChannel::BaseEndpointChannel(absl::string_view channel_name, - Ptr reader, - Ptr writer) - : last_read_timestamp_(-1), - channel_name_(channel_name), - system_clock_(Platform::createSystemClock()), - reader_lock_(Platform::createLock()), - reader_(reader), - writer_lock_(Platform::createLock()), - writer_(writer), - encryption_context_(Platform::createAtomicReference( - Ptr())), - is_paused_lock_(Platform::createLock()), - is_paused_condition_variable_( - Platform::createConditionVariable(is_paused_lock_.get())), - is_paused_(Platform::createAtomicBoolean(false)) {} +BaseEndpointChannel::BaseEndpointChannel(const std::string& channel_name, + InputStream* reader, + OutputStream* writer) + : channel_name_(channel_name), reader_(reader), writer_(writer) {} -BaseEndpointChannel::~BaseEndpointChannel() { - // WARNING: Make sure to never access reader_ and writer_ from here. - // - // They're owned by the specialized *Socket classes that are in turn - // owned by the *EndpointChannel children of this class, so by this point, - // they've been destroyed and now point to invalid memory. - // - // "Ugh!" is right -- this won't be a problem once we have a standardized - // Socket interface we can hold up in this class (instead of holding - // specialized implementations of that hypothetical interface in each child - // of this class). +ExceptionOr BaseEndpointChannel::Read() { + ByteArray result; + { + MutexLock lock(&reader_mutex_); + + ExceptionOr read_int = ReadInt(reader_); + if (!read_int.ok()) { + return ExceptionOr(read_int.exception()); + } + + if (read_int.result() < 0 || read_int.result() > kMaxAllowedReadBytes) { + return ExceptionOr(Exception::kIo); + } + + ExceptionOr read_bytes = ReadExactly(reader_, read_int.result()); + if (!read_bytes.ok()) { + return read_bytes; + } + result = std::move(read_bytes.result()); + } + + { + MutexLock crypto_lock(&crypto_mutex_); + if (IsEncryptionEnabledLocked()) { + // If encryption is enabled, decode the message. + std::string input(std::move(result)); + std::unique_ptr decrypted_data = + crypto_context_->DecodeMessageFromPeer(input); + if (decrypted_data) { + result = ByteArray(std::move(*decrypted_data)); + } else { + // It could be a protocol race, where remote party sends a KEEP_ALIVE + // before encryption is setup on their side, and we receive it after + // we switched to encryption mode. + // In this case, we verify that message is indeed a valid KEEP_ALIVE, + // and let it through if it is, otherwise message is erased. + // TODO(apolyudov): verify this happens at most once per session. + result = {}; + auto parsed = parser::FromBytes(ByteArray(input)); + if (parsed.ok() && + parser::GetFrameType(parsed.result()) == V1Frame::KEEP_ALIVE) { + result = ByteArray(input); + } + } + if (result.Empty()) { + return ExceptionOr(Exception::kInvalidProtocolBuffer); + } + } + } + + { + MutexLock lock(&last_read_mutex_); + last_read_timestamp_ = SystemClock::ElapsedRealtime(); + } + return ExceptionOr(result); } -ExceptionOr> BaseEndpointChannel::read() { - Synchronized s(reader_lock_.get()); - - ExceptionOr read_int = readInt(reader_); - if (!read_int.ok()) { - if (Exception::IO == read_int.exception()) { - return ExceptionOr>(read_int.exception()); +Exception BaseEndpointChannel::Write(const ByteArray& data) { + { + MutexLock pause_lock(&is_paused_mutex_); + if (is_paused_) { + BlockUntilUnpaused(); } } - if (read_int.result() < 0) { - return ExceptionOr>(Exception::IO); - } else if (read_int.result() > kMaxAllowedReadBytes) { - return ExceptionOr>(Exception::IO); - } - - ExceptionOr> read_bytes = - readExactly(reader_, read_int.result()); - if (!read_bytes.ok()) { - if (Exception::IO == read_bytes.exception()) { - return ExceptionOr>(read_bytes.exception()); + ByteArray encrypted_data; + const ByteArray* data_to_write = &data; + { + MutexLock crypto_lock(&crypto_mutex_); + if (IsEncryptionEnabledLocked()) { + // If encryption is enabled, encode the message. + std::unique_ptr encrypted = + crypto_context_->EncodeMessageToPeer(std::string(data)); + if (!encrypted) return {Exception::kIo}; + encrypted_data = ByteArray(std::move(*encrypted)); + data_to_write = &encrypted_data; } } - // This should be ScopedPtr usually, but because of the unique requirement of - // reassigning this variable when encryption is enabled, we can't make use of - // the power of ScopedPtr, and instead have to do manual memory management. - ConstPtr read_bytes_result = read_bytes.result(); - - // If encryption is enabled, decode the message. - if (isEncryptionEnabled()) { - std::unique_ptr decoded_bytes = - encryption_context_->get()->DecodeMessageFromPeer( - string(read_bytes_result->getData(), read_bytes_result->size())); - // Now that we are done using read_bytes_result, we should unconditionally - // destroy it, because we either reassign to the value of decoded_bytes, or - // short-circuit out of here on error. - read_bytes_result.destroy(); - if (decoded_bytes == nullptr) { - return ExceptionOr>( - Exception::INVALID_PROTOCOL_BUFFER); - } - read_bytes_result = MakeConstPtr( - new ByteArray(decoded_bytes->data(), decoded_bytes->size())); - } - - last_read_timestamp_ = system_clock_->elapsedRealtime(); - return ExceptionOr>(read_bytes_result); -} - -Exception::Value BaseEndpointChannel::write(ConstPtr data) { - Synchronized s(writer_lock_.get()); - - // Avoid leaks. - ScopedPtr> scoped_data(data); - - if (isPaused()) { - blockUntilUnpaused(); - } - - ConstPtr data_to_write; - // If encryption is enabled, encode the message. - if (isEncryptionEnabled()) { - std::unique_ptr message = - encryption_context_->get()->EncodeMessageToPeer( - string(scoped_data->getData(), scoped_data->size())); - assert(message != nullptr); - data_to_write = - MakeConstPtr(new ByteArray(message->data(), message->size())); - } else { - // Else, just make data_to_write point to the passed-in data. - data_to_write = scoped_data.release(); - } - // Avoid leaks. - ScopedPtr> scoped_data_to_write(data_to_write); - - Exception::Value write_exception = writeInt( - writer_, static_cast(scoped_data_to_write->size())); - if (Exception::NONE != write_exception) { - if (Exception::IO == write_exception) { + { + MutexLock lock(&writer_mutex_); + Exception write_exception = + WriteInt(writer_, static_cast(data_to_write->size())); + if (write_exception.Raised()) { return write_exception; } - } - - write_exception = writer_->write(scoped_data_to_write.release()); - if (Exception::NONE != write_exception) { - if (Exception::IO == write_exception) { + write_exception = writer_->Write(*data_to_write); + if (write_exception.Raised()) { return write_exception; } - } - - Exception::Value flush_exception = writer_->flush(); - if (Exception::NONE != flush_exception) { - if (Exception::IO == flush_exception) { + Exception flush_exception = writer_->Flush(); + if (flush_exception.Raised()) { return flush_exception; } } - return Exception::NONE; + return {Exception::kSuccess}; } -void BaseEndpointChannel::close() { - // WARNING WARNING WARNING - // - // This block deviates from the corresponding Java code. - // - // In the corresponding Java code, close() calls - // close(proto::connections::DisconnectionReason) while here we do the - // opposite. This is because proto::connections::DisconnectionReason can be - // null in Java but not in C++. - Exception::Value reader_close_exception = reader_->close(); - if (Exception::NONE != reader_close_exception) { - if (Exception::IO == reader_close_exception) { +void BaseEndpointChannel::Close() { + { + // In case channel is paused, resume it first thing. + MutexLock lock(&is_paused_mutex_); + UnblockPausedWriter(); + } + CloseIo(); + CloseImpl(); +} + +void BaseEndpointChannel::CloseIo() { + // Keep this method dedicated to reader and writer handling an nothing else. + { + // Do not take reader_mutex_ here: read may be in progress, and it will + // deadlock. Calling Close() with Read() in progress will terminate the + // IO and Read() will proceed normally (with Exception::kIo). + Exception exception = reader_->Close(); + if (!exception.Ok()) { // Add logging. } } - Exception::Value writer_close_exception = writer_->close(); - if (Exception::NONE != writer_close_exception) { - if (Exception::IO == writer_close_exception) { + { + // Do not take writer_mutex_ here: write may be in progress, and it will + // deadlock. Calling Close() with Write() in progress will terminate the + // IO and Write() will proceed normally (with Exception::kIo). + Exception exception = writer_->Close(); + if (!exception.Ok()) { // Add logging. } } - - closeImpl(); - - // TODO(tracyzhou): Add logging. } -void BaseEndpointChannel::close( +void BaseEndpointChannel::Close( proto::connections::DisconnectionReason reason) { - // WARNING WARNING WARNING - // - // This block deviates from the corresponding Java code. - // Look at the corresponding block in the close() method above for details on - // the deviation. - close(); - - // TODO(tracyzhou): Add logging. + Close(); } -string BaseEndpointChannel::getType() { - string subtype = isEncryptionEnabled() ? "ENCRYPTED_" : ""; - switch (getMedium()) { +std::string BaseEndpointChannel::GetType() const { + MutexLock crypto_lock(&crypto_mutex_); + std::string subtype = IsEncryptionEnabledLocked() ? "ENCRYPTED_" : ""; + + switch (GetMedium()) { case proto::connections::Medium::BLUETOOTH: - return subtype + "BLUETOOTH"; + return absl::StrCat(subtype, "BLUETOOTH"); case proto::connections::Medium::BLE: - return subtype + "BLE"; + return absl::StrCat(subtype, "BLE"); case proto::connections::Medium::MDNS: - return subtype + "MDNS"; + return absl::StrCat(subtype, "MDNS"); case proto::connections::Medium::WIFI_HOTSPOT: - return subtype + "WIFI_HOTSPOT"; + return absl::StrCat(subtype, "WIFI_HOTSPOT"); case proto::connections::Medium::WIFI_LAN: - return subtype + "WIFI_LAN"; + return absl::StrCat(subtype, "WIFI_LAN"); default: return "UNKNOWN"; } } -string BaseEndpointChannel::getName() { return channel_name_; } +std::string BaseEndpointChannel::GetName() const { return channel_name_; } -void BaseEndpointChannel::enableEncryption( - Ptr encryption_context) { - assert(!encryption_context.isNull()); - encryption_context_->set(encryption_context); +void BaseEndpointChannel::EnableEncryption( + std::shared_ptr context) { + MutexLock crypto_lock(&crypto_mutex_); + crypto_context_ = context; } -bool BaseEndpointChannel::isPaused() { return is_paused_->get(); } - -void BaseEndpointChannel::pause() { is_paused_->set(true); } - -void BaseEndpointChannel::resume() { - is_paused_->set(false); - unblockPausedWriter(); +bool BaseEndpointChannel::IsPaused() const { + MutexLock lock(&is_paused_mutex_); + return is_paused_; } -std::int64_t BaseEndpointChannel::getLastReadTimestamp() { +void BaseEndpointChannel::Pause() { + MutexLock lock(&is_paused_mutex_); + is_paused_ = true; +} + +void BaseEndpointChannel::Resume() { + MutexLock lock(&is_paused_mutex_); + is_paused_ = false; + is_paused_cond_.Notify(); +} + +absl::Time BaseEndpointChannel::GetLastReadTimestamp() const { + MutexLock lock(&last_read_mutex_); return last_read_timestamp_; } -bool BaseEndpointChannel::isEncryptionEnabled() { - return !encryption_context_->get().isNull(); +bool BaseEndpointChannel::IsEncryptionEnabledLocked() const { + return crypto_context_ != nullptr; } -void BaseEndpointChannel::unblockPausedWriter() { - Synchronized s(is_paused_lock_.get()); - - // Notify to tell the thread calling wait() to check again. - // NOTE: There is only ever one thread blocked by wait() at a time, because - // EndpointChannel.write(Ptr) is synchronized on writer. That means - // the first thread to call write(byte[]) will be blocked via - // blockUntilUnpaused() and all future threads will be blocked via - // synchronized(writer_lock_). - is_paused_condition_variable_->notify(); -} - -void BaseEndpointChannel::blockUntilUnpaused() { - Synchronized s(is_paused_lock_.get()); - +void BaseEndpointChannel::BlockUntilUnpaused() { // For more on how this works, see // https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html - while (is_paused_->get()) { - Exception::Value wait_succeeded = is_paused_condition_variable_->wait(); - if (Exception::NONE != wait_succeeded) { - if (Exception::INTERRUPTED == wait_succeeded) { - // If we were interrupted, pass the interrupt up the stack and then exit - // immediately. - // Thread.currentThread().interrupt(); - return; - } + while (is_paused_) { + Exception wait_succeeded = is_paused_cond_.Wait(); + if (!wait_succeeded.Ok()) { + return; } } } +void BaseEndpointChannel::UnblockPausedWriter() { + // For more on how this works, see + // https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html + is_paused_ = false; + is_paused_cond_.Notify(); +} + } // namespace connections } // namespace nearby } // namespace location diff --git a/cpp/core/internal/base_endpoint_channel.h b/cpp/core/internal/base_endpoint_channel.h index e5b60160..10285aa1 100644 --- a/cpp/core/internal/base_endpoint_channel.h +++ b/cpp/core/internal/base_endpoint_channel.h @@ -2,21 +2,20 @@ #define CORE_INTERNAL_BASE_ENDPOINT_CHANNEL_H_ #include +#include +#include #include "core/internal/endpoint_channel.h" -#include "platform/api/atomic_boolean.h" -#include "platform/api/atomic_reference.h" -#include "platform/api/condition_variable.h" -#include "platform/api/input_stream.h" -#include "platform/api/lock.h" -#include "platform/api/output_stream.h" -#include "platform/api/system_clock.h" -#include "platform/byte_array.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "platform/base/byte_array.h" +#include "platform/base/input_stream.h" +#include "platform/base/output_stream.h" +#include "platform/public/atomic_reference.h" +#include "platform/public/condition_variable.h" +#include "platform/public/mutex.h" +#include "platform/public/system_clock.h" #include "proto/connections_enums.pb.h" #include "securegcm/d2d_connection_context_v1.h" -#include "absl/strings/string_view.h" +#include "absl/base/thread_annotations.h" namespace location { namespace nearby { @@ -24,83 +23,88 @@ namespace connections { class BaseEndpointChannel : public EndpointChannel { public: - BaseEndpointChannel(absl::string_view channel_name, Ptr reader, - Ptr writer); - ~BaseEndpointChannel() override; + BaseEndpointChannel(const std::string& channel_name, InputStream* reader, + OutputStream* writer); + ~BaseEndpointChannel() override = default; - ExceptionOr > read() override; + ExceptionOr Read() + ABSL_LOCKS_EXCLUDED(reader_mutex_, crypto_mutex_, + last_read_mutex_) override; - Exception::Value write(ConstPtr data) override; + Exception Write(const ByteArray& data) + ABSL_LOCKS_EXCLUDED(writer_mutex_, crypto_mutex_) override; // Closes this EndpointChannel, without tracking the closure in analytics. - void close() override; + void Close() ABSL_LOCKS_EXCLUDED(is_paused_mutex_) override; // Closes this EndpointChannel and records the closure with the given reason. - void close(proto::connections::DisconnectionReason reason) override; + void Close(proto::connections::DisconnectionReason reason) override; // Returns a one-word type descriptor for the concrete EndpointChannel // implementation that can be used in log messages; eg: BLUETOOTH, BLE, // WIFI. - string getType() override; + std::string GetType() const override; // Returns the name of the EndpointChannel. - string getName() override; + std::string GetName() const override; // Enables encryption on the EndpointChannel. - void enableEncryption( - Ptr encryption_context) override; + // Should be called after connection is accepted by both parties, and + // before entering data phase, where Payloads may be exchanged. + void EnableEncryption(std::shared_ptr context) override; // True if the EndpointChannel is currently pausing all writes. - bool isPaused() override; + bool IsPaused() const ABSL_LOCKS_EXCLUDED(is_paused_mutex_) override; // Pauses all writes on this EndpointChannel until resume() is called. - void pause() override; + void Pause() ABSL_LOCKS_EXCLUDED(is_paused_mutex_) override; // Resumes any writes on this EndpointChannel that were suspended when pause() // was called. - void resume() override; + void Resume() ABSL_LOCKS_EXCLUDED(is_paused_mutex_) override; - // Returns the timestamp (in elapsedRealtime) of the last read from this - // endpoint, or -1 if no reads have occurred. - std::int64_t getLastReadTimestamp() override; + // Returns the timestamp (returned by ElapsedRealtime) of the last read from + // this endpoint, or -1 if no reads have occurred. + absl::Time GetLastReadTimestamp() const + ABSL_LOCKS_EXCLUDED(last_read_mutex_) override; protected: - virtual void closeImpl() = 0; + virtual void CloseImpl() = 0; private: // Used to sanity check that our frame sizes are reasonable. static constexpr std::int32_t kMaxAllowedReadBytes = 1048576; // 1MB - bool isEncryptionEnabled(); - void unblockPausedWriter(); - void blockUntilUnpaused(); + bool IsEncryptionEnabledLocked() const + ABSL_EXCLUSIVE_LOCKS_REQUIRED(crypto_mutex_); + void UnblockPausedWriter() ABSL_EXCLUSIVE_LOCKS_REQUIRED(is_paused_mutex_); + void BlockUntilUnpaused() ABSL_EXCLUSIVE_LOCKS_REQUIRED(is_paused_mutex_); + void CloseIo() ABSL_NO_THREAD_SAFETY_ANALYSIS; - volatile std::int64_t last_read_timestamp_; - - const string channel_name_; - - ScopedPtr > system_clock_; + // We need a separate mutex to pritect read timestamp, because if a read + // blocks on IO, we don't want timestamp read access to block too. + mutable Mutex last_read_mutex_; + absl::Time last_read_timestamp_ ABSL_GUARDED_BY(last_read_mutex_) = + absl::InfinitePast(); + const std::string channel_name_; // The reader and writer are synchronized independently since we can't have // writes waiting on reads that might potentially block forever. - ScopedPtr > reader_lock_; - // Not owned by this class, see the note in the destructor for a special - // restriction on usage. - Ptr reader_; + Mutex reader_mutex_; + InputStream* reader_ ABSL_PT_GUARDED_BY(reader_mutex_); - ScopedPtr > writer_lock_; - // Not owned by this class, see the note in the destructor for a special - // restriction on usage. - Ptr writer_; + Mutex writer_mutex_; + OutputStream* writer_ ABSL_PT_GUARDED_BY(writer_mutex_); // An encryptor/decryptor. May be null. - ScopedPtr > > > - encryption_context_; + mutable Mutex crypto_mutex_; + std::shared_ptr crypto_context_ + ABSL_GUARDED_BY(crypto_mutex_) ABSL_PT_GUARDED_BY(crypto_mutex_); - ScopedPtr > is_paused_lock_; - ScopedPtr > is_paused_condition_variable_; + mutable Mutex is_paused_mutex_; + ConditionVariable is_paused_cond_{&is_paused_mutex_}; // If true, writes should block until this has been set to false. - ScopedPtr > is_paused_; + bool is_paused_ ABSL_GUARDED_BY(is_paused_mutex_) = false; }; } // namespace connections diff --git a/cpp/core/internal/base_endpoint_channel_test.cc b/cpp/core/internal/base_endpoint_channel_test.cc index f954758a..e8f16533 100644 --- a/cpp/core/internal/base_endpoint_channel_test.cc +++ b/cpp/core/internal/base_endpoint_channel_test.cc @@ -1,43 +1,339 @@ #include "core/internal/base_endpoint_channel.h" -#include "platform/api/platform.h" -#include "platform/pipe.h" +#include + +#include "core/internal/encryption_runner.h" +#include "platform/base/byte_array.h" +#include "platform/base/input_stream.h" +#include "platform/base/output_stream.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/logging.h" +#include "platform/public/multi_thread_executor.h" +#include "platform/public/pipe.h" +#include "platform/public/single_thread_executor.h" #include "proto/connections_enums.pb.h" +#include "proto/connections_enums.pb.h" +#include "securegcm/d2d_connection_context_v1.h" +#include "securegcm/ukey2_handshake.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/synchronization/mutex.h" +#include "absl/time/time.h" namespace location { namespace nearby { namespace connections { namespace { +using ::location::nearby::proto::connections::DisconnectionReason; +using ::location::nearby::proto::connections::Medium; +using EncryptionContext = BaseEndpointChannel::EncryptionContext; + class TestEndpointChannel : public BaseEndpointChannel { public: - explicit TestEndpointChannel(Ptr input_stream) - : BaseEndpointChannel("channel", input_stream, Ptr()) {} + explicit TestEndpointChannel(InputStream* input, OutputStream* output) + : BaseEndpointChannel("channel", input, output) {} - MOCK_METHOD(proto::connections::Medium, getMedium, (), (override)); - MOCK_METHOD(void, closeImpl, (), (override)); + MOCK_METHOD(Medium, GetMedium, (), (const override)); + MOCK_METHOD(void, CloseImpl, (), (override)); }; -using SamplePipe = Pipe; +std::function MakeDataPump( + std::string label, InputStream* input, OutputStream* output, + std::function monitor = nullptr) { + return [label, input, output, monitor]() { + NEARBY_LOG(INFO, "streaming data thorough '%s'", label.c_str()); + while (true) { + auto read_response = input->Read(Pipe::kChunkSize); + if (!read_response.ok()) { + NEARBY_LOG(INFO, "Peer reader closed on '%s'", label.c_str()); + output->Close(); + break; + } + if (monitor) { + monitor(read_response.result()); + } + auto write_response = output->Write(read_response.result()); + if (write_response.Raised()) { + NEARBY_LOG(INFO, "Peer writer closed on '%s'", label.c_str()); + input->Close(); + break; + } + } + NEARBY_LOG(INFO, "streaming terminated on '%s'", label.c_str()); + }; +} + +std::function MakeDataMonitor(const std::string& label, + std::string* capture, + absl::Mutex* mutex) { + return [label, capture, mutex](const ByteArray& input) mutable { + std::string s = std::string(input); + { + absl::MutexLock lock(mutex); + *capture += s; + } + NEARBY_LOG(INFO, "source='%s'; message='%s'", label.c_str(), s.c_str()); + }; +} + +std::pair, + std::shared_ptr> +DoDhKeyExchange(BaseEndpointChannel* channel_a, + BaseEndpointChannel* channel_b) { + std::shared_ptr context_a; + std::shared_ptr context_b; + EncryptionRunner crypto_a; + EncryptionRunner crypto_b; + ClientProxy proxy_a; + ClientProxy proxy_b; + CountDownLatch latch(2); + crypto_a.StartClient( + &proxy_a, "endpoint_id", channel_a, + { + .on_success_cb = + [&latch, &context_a]( + const string& endpoint_id, + std::unique_ptr ukey2, + const string& auth_token, const ByteArray& raw_auth_token) { + NEARBY_LOG(INFO, "client-A side key negotiation done"); + EXPECT_TRUE(ukey2->VerifyHandshake()); + auto context = ukey2->ToConnectionContext(); + EXPECT_NE(context, nullptr); + context_a = std::move(context); + latch.CountDown(); + }, + .on_failure_cb = + [&latch](const string& endpoint_id, EndpointChannel* channel) { + NEARBY_LOG(INFO, "client-A side key negotiation failed"); + latch.CountDown(); + }, + }); + crypto_b.StartServer( + &proxy_b, "endpoint_id", channel_b, + { + .on_success_cb = + [&latch, &context_b]( + const string& endpoint_id, + std::unique_ptr ukey2, + const string& auth_token, const ByteArray& raw_auth_token) { + NEARBY_LOG(INFO, "client-B side key negotiation done"); + EXPECT_TRUE(ukey2->VerifyHandshake()); + auto context = ukey2->ToConnectionContext(); + EXPECT_NE(context, nullptr); + context_b = std::move(context); + latch.CountDown(); + }, + .on_failure_cb = + [&latch](const string& endpoint_id, EndpointChannel* channel) { + NEARBY_LOG(INFO, "client-B side key negotiation failed"); + latch.CountDown(); + }, + }); + EXPECT_TRUE(latch.Await(absl::Milliseconds(5000)).result()); + return std::make_pair(std::move(context_a), std::move(context_b)); +} + +TEST(BaseEndpointChannelTest, ConstructorDestructorWorks) { + Pipe pipe; + InputStream& input_stream = pipe.GetInputStream(); + OutputStream& output_stream = pipe.GetOutputStream(); + + TestEndpointChannel test_channel(&input_stream, &output_stream); +} + +TEST(BaseEndpointChannelTest, ReadWrite) { + // Direct not-encrypted IO. + Pipe pipe_a; // channel_a writes to pipe_a, reads from pipe_b. + Pipe pipe_b; // channel_b writes to pipe_b, reads from pipe_a. + TestEndpointChannel channel_a(&pipe_b.GetInputStream(), + &pipe_a.GetOutputStream()); + TestEndpointChannel channel_b(&pipe_a.GetInputStream(), + &pipe_b.GetOutputStream()); + ByteArray tx_message{"data message"}; + channel_a.Write(tx_message); + ByteArray rx_message = std::move(channel_b.Read().result()); + EXPECT_EQ(rx_message, tx_message); +} + +TEST(BaseEndpointChannelTest, NotEncryptedReadWriteCanBeIntercepted) { + // Not encrypted IO; MITM scenario. + + // Setup test communication environment. + absl::Mutex mutex; + std::string capture_a; + std::string capture_b; + Pipe client_a; // Channel "a" writes to client "a", reads from server "a". + Pipe client_b; // Channel "b" writes to client "b", reads from server "b". + Pipe server_a; // Data pump "a" reads from client "a", writes to server "b". + Pipe server_b; // Data pump "b" reads from client "b", writes to server "a". + TestEndpointChannel channel_a(&server_a.GetInputStream(), + &client_a.GetOutputStream()); + TestEndpointChannel channel_b(&server_b.GetInputStream(), + &client_b.GetOutputStream()); + + ON_CALL(channel_a, GetMedium).WillByDefault([]() { return Medium::BLE; }); + ON_CALL(channel_b, GetMedium).WillByDefault([]() { return Medium::BLE; }); + + MultiThreadExecutor executor(2); + executor.Execute(MakeDataPump( + "pump_a", &client_a.GetInputStream(), &server_b.GetOutputStream(), + MakeDataMonitor("monitor_a", &capture_a, &mutex))); + executor.Execute(MakeDataPump( + "pump_b", &client_b.GetInputStream(), &server_a.GetOutputStream(), + MakeDataMonitor("monitor_b", &capture_b, &mutex))); + + EXPECT_EQ(channel_a.GetType(), "BLE"); + EXPECT_EQ(channel_b.GetType(), "BLE"); + + // Start data transfer + ByteArray tx_message{"data message"}; + channel_a.Write(tx_message); + ByteArray rx_message = std::move(channel_b.Read().result()); + + // Verify expectations. + EXPECT_EQ(rx_message, tx_message); + { + absl::MutexLock lock(&mutex); + std::string message{tx_message}; + EXPECT_TRUE(capture_a.find(message) != std::string::npos || + capture_b.find(message) != std::string::npos); + } + + // Shutdown test environment. + channel_a.Close(DisconnectionReason::LOCAL_DISCONNECTION); + channel_b.Close(DisconnectionReason::REMOTE_DISCONNECTION); +} + +TEST(BaseEndpointChannelTest, EncryptedReadWriteCanNotBeIntercepted) { + // Encrypted IO; MITM scenario. + + // Setup test communication environment. + absl::Mutex mutex; + std::string capture_a; + std::string capture_b; + Pipe client_a; // Channel "a" writes to client "a", reads from server "a". + Pipe client_b; // Channel "b" writes to client "b", reads from server "b". + Pipe server_a; // Data pump "a" reads from client "a", writes to server "b". + Pipe server_b; // Data pump "b" reads from client "b", writes to server "a". + TestEndpointChannel channel_a(&server_a.GetInputStream(), + &client_a.GetOutputStream()); + TestEndpointChannel channel_b(&server_b.GetInputStream(), + &client_b.GetOutputStream()); + + ON_CALL(channel_a, GetMedium).WillByDefault([]() { + return Medium::BLUETOOTH; + }); + ON_CALL(channel_b, GetMedium).WillByDefault([]() { + return Medium::BLUETOOTH; + }); + + MultiThreadExecutor executor(2); + executor.Execute(MakeDataPump( + "pump_a", &client_a.GetInputStream(), &server_b.GetOutputStream(), + MakeDataMonitor("monitor_a", &capture_a, &mutex))); + executor.Execute(MakeDataPump( + "pump_b", &client_b.GetInputStream(), &server_a.GetOutputStream(), + MakeDataMonitor("monitor_b", &capture_b, &mutex))); + + // Run DH key exchange; setup encryption contexts for channels. + auto [context_a, context_b] = DoDhKeyExchange(&channel_a, &channel_b); + ASSERT_NE(context_a, nullptr); + ASSERT_NE(context_b, nullptr); + channel_a.EnableEncryption(context_a); + channel_b.EnableEncryption(context_b); + + EXPECT_EQ(channel_a.GetType(), "ENCRYPTED_BLUETOOTH"); + EXPECT_EQ(channel_b.GetType(), "ENCRYPTED_BLUETOOTH"); + + // Start data transfer + ByteArray tx_message{"data message"}; + channel_a.Write(tx_message); + ByteArray rx_message = std::move(channel_b.Read().result()); + + // Verify expectations. + EXPECT_EQ(rx_message, tx_message); + { + absl::MutexLock lock(&mutex); + std::string message{tx_message}; + EXPECT_TRUE(capture_a.find(message) == std::string::npos && + capture_b.find(message) == std::string::npos); + } + + // Shutdown test environment. + channel_a.Close(DisconnectionReason::LOCAL_DISCONNECTION); + channel_b.Close(DisconnectionReason::REMOTE_DISCONNECTION); +} + +TEST(BaseEndpointChannelTest, CanBesuspendedAndResumed) { + // Setup test communication environment. + Pipe pipe_a; // channel_a writes to pipe_a, reads from pipe_b. + Pipe pipe_b; // channel_b writes to pipe_b, reads from pipe_a. + TestEndpointChannel channel_a(&pipe_b.GetInputStream(), + &pipe_a.GetOutputStream()); + TestEndpointChannel channel_b(&pipe_a.GetInputStream(), + &pipe_b.GetOutputStream()); + + ON_CALL(channel_a, GetMedium).WillByDefault([]() { + return Medium::WIFI_LAN; + }); + ON_CALL(channel_b, GetMedium).WillByDefault([]() { + return Medium::WIFI_LAN; + }); + + EXPECT_EQ(channel_a.GetType(), "WIFI_LAN"); + EXPECT_EQ(channel_b.GetType(), "WIFI_LAN"); + + // Start data transfer + ByteArray tx_message{"data message"}; + ByteArray more_message{"more data"}; + channel_a.Write(tx_message); + ByteArray rx_message = std::move(channel_b.Read().result()); + + // Pause and make sure reader blocks. + MultiThreadExecutor pause_resume_executor(2); + channel_a.Pause(); + pause_resume_executor.Execute([&channel_a, &more_message]() { + // Write will block until channel is resumed, or closed. + EXPECT_TRUE(channel_a.Write(more_message).Ok()); + }); + CountDownLatch latch(1); + ByteArray read_more; + pause_resume_executor.Execute([&channel_b, &read_more, &latch]() { + // Read will block until channel is resumed, or closed. + auto response = channel_b.Read(); + EXPECT_TRUE(response.ok()); + read_more = std::move(response.result()); + latch.CountDown(); + }); + absl::SleepFor(absl::Milliseconds(500)); + EXPECT_TRUE(read_more.Empty()); + + // Resume; verify that data transfer comepleted. + channel_a.Resume(); + EXPECT_TRUE(latch.Await(absl::Milliseconds(1000)).result()); + EXPECT_EQ(read_more, more_message); + + // Shutdown test environment. + channel_a.Close(DisconnectionReason::LOCAL_DISCONNECTION); + channel_b.Close(DisconnectionReason::REMOTE_DISCONNECTION); +} TEST(BaseEndpointChannelTest, ReadAfterInputStreamClosed) { - auto pipe = MakeRefCountedPtr(new SamplePipe()); - ScopedPtr> input_stream(SamplePipe::createInputStream(pipe)); - ScopedPtr> output_stream( - SamplePipe::createOutputStream(pipe)); + Pipe pipe; + InputStream& input_stream = pipe.GetInputStream(); + OutputStream& output_stream = pipe.GetOutputStream(); - TestEndpointChannel test_channel(input_stream.get()); + TestEndpointChannel test_channel(&input_stream, &output_stream); // Close the output stream before trying to read from the input. - output_stream->close(); + output_stream.Close(); // Trying to read should fail gracefully with an IO error. - ExceptionOr> result = test_channel.read(); + ExceptionOr read_data = test_channel.Read(); - ASSERT_FALSE(result.ok()); - ASSERT_EQ(Exception::IO, result.exception()); + ASSERT_FALSE(read_data.ok()); + ASSERT_TRUE(read_data.GetException().Raised(Exception::kIo)); } } // namespace diff --git a/cpp/core/internal/base_pcp_handler.cc b/cpp/core/internal/base_pcp_handler.cc index 03235508..6d74be82 100644 --- a/cpp/core/internal/base_pcp_handler.cc +++ b/cpp/core/internal/base_pcp_handler.cc @@ -4,1201 +4,937 @@ #include #include #include +#include + +#include "core/internal/offline_frames.h" +#include "core/internal/pcp_handler.h" +#include "core/options.h" +#include "platform/base/bluetooth_utils.h" +#include "platform/public/logging.h" +#include "platform/public/system_clock.h" +#include "securegcm/d2d_connection_context_v1.h" +#include "securegcm/ukey2_handshake.h" +#include "absl/container/flat_hash_set.h" +#include "absl/strings/escaping.h" +#include "absl/types/span.h" namespace location { namespace nearby { namespace connections { -namespace base_pcp_handler { +using ::location::nearby::proto::connections::Medium; +using ::securegcm::UKey2Handshake; -// TODO(reznor): Implement this method in-terms-of removeOwnedPtrFromMap() -// below. -template -void eraseOwnedPtrFromMap(std::map>& m, const K& k) { - typename std::map>::iterator it = m.find(k); - if (it != m.end()) { - it->second.destroy(); - m.erase(it); - } +constexpr absl::Duration BasePcpHandler::kConnectionRequestReadTimeout; +constexpr absl::Duration BasePcpHandler::kRejectedConnectionCloseDelay; + +BasePcpHandler::BasePcpHandler(Mediums* mediums, + EndpointManager* endpoint_manager, + EndpointChannelManager* channel_manager, + BwuManager* bwu_manager, Pcp pcp) + : mediums_(mediums), + endpoint_manager_(endpoint_manager), + channel_manager_(channel_manager), + pcp_(pcp), + bwu_manager_(bwu_manager) {} + +BasePcpHandler::~BasePcpHandler() { + NEARBY_LOGS(INFO) << "BasePcpHandler: going down; strategy=" + << strategy_.GetName() << "; handle=" << handle_; + DisconnectFromEndpointManager(); + // Stop all the ongoing Runnables (as gracefully as possible). + NEARBY_LOGS(INFO) << "BasePcpHandler: bringing down executors; strategy=" + << strategy_.GetName(); + serial_executor_.Shutdown(); + alarm_executor_.Shutdown(); + NEARBY_LOGS(INFO) << "BasePcpHandler: is down; strategy=" + << strategy_.GetName(); } -template -Ptr removeOwnedPtrFromMap(std::map>& m, const K& k) { - Ptr removed_ptr; - - typename std::map>::iterator it = m.find(k); - if (it != m.end()) { - removed_ptr = it->second; - m.erase(it); - } - - return removed_ptr; +void BasePcpHandler::DisconnectFromEndpointManager() { + if (stop_.Set(true)) return; + NEARBY_LOGS(INFO) << "BasePcpHandler: Unregister from EPM; strategy=" + << strategy_.GetName() << "; handle=" << handle_; + // Unregister ourselves from EPM message dispatcher. + endpoint_manager_->UnregisterFrameProcessor(V1Frame::CONNECTION_RESPONSE, + handle_, true); } -template -class StartAdvertisingCallable : public Callable { - public: - StartAdvertisingCallable( - Ptr> base_pcp_handler, - Ptr> client_proxy, const string& service_id, - const string& local_endpoint_name, const AdvertisingOptions& options, - Ptr connection_lifecycle_listener) - : base_pcp_handler_(base_pcp_handler), - client_proxy_(client_proxy), - service_id_(service_id), - local_endpoint_name_(local_endpoint_name), - options_(options), - connection_lifecycle_listener_(connection_lifecycle_listener) {} - - ExceptionOr call() override { - // Ask the implementation to attempt to start advertising. - ScopedPtr::StartOperationResult>> - result(base_pcp_handler_->startAdvertisingImpl( - client_proxy_, service_id_, - client_proxy_->generateLocalEndpointId(), local_endpoint_name_, - options_)); - if (Status::SUCCESS != result->status_) { - return ExceptionOr(result->status_); +Status BasePcpHandler::StartAdvertising(ClientProxy* client, + const std::string& service_id, + const ConnectionOptions& options, + const ConnectionRequestInfo& info) { + Future response; + ConnectionOptions advertising_options = options.CompatibleOptions(); + RunOnPcpHandlerThread([this, client, &service_id, &info, &advertising_options, + &response]() { + auto result = + StartAdvertisingImpl(client, service_id, client->GetLocalEndpointId(), + info.endpoint_info, advertising_options); + if (!result.status.Ok()) { + response.Set(result.status); + return; } // Now that we've succeeded, mark the client as advertising. - // Previous advertising_options_ and - // advertising_connection_lifecycle_listener_ is not destroyed here because - // stopAdvertising() is expected to be called before startAdvertising(). - base_pcp_handler_->advertising_options_ = - MakePtr(new AdvertisingOptions(options_)); - base_pcp_handler_->advertising_connection_lifecycle_listener_ = - connection_lifecycle_listener_; - client_proxy_->startedAdvertising( - service_id_, base_pcp_handler_->getStrategy(), - connection_lifecycle_listener_, result->mediums_); - return ExceptionOr(Status::SUCCESS); - } + advertising_options_ = advertising_options; + advertising_listener_ = info.listener; + client->StartedAdvertising(service_id, GetStrategy(), info.listener, + absl::MakeSpan(result.mediums)); + response.Set({Status::kSuccess}); + }); + return WaitForResult( + absl::StrCat("StartAdvertising(", std::string(info.endpoint_info), ")"), + client->GetClientId(), &response); +} - private: - Ptr> base_pcp_handler_; - Ptr> client_proxy_; - const string service_id_; - const string local_endpoint_name_; - const AdvertisingOptions options_; - Ptr connection_lifecycle_listener_; -}; +void BasePcpHandler::StopAdvertising(ClientProxy* client) { + CountDownLatch latch(1); + RunOnPcpHandlerThread([this, client, &latch]() { + StopAdvertisingImpl(client); + client->StoppedAdvertising(); + advertising_options_.Clear(); + latch.CountDown(); + }); + WaitForLatch("StopAdvertising", &latch); +} -template -class StopAdvertisingRunnable : public Runnable { - public: - StopAdvertisingRunnable(Ptr> base_pcp_handler, - Ptr> client_proxy, - Ptr latch) - : base_pcp_handler_(base_pcp_handler), - client_proxy_(client_proxy), - latch_(latch) {} +Status BasePcpHandler::StartDiscovery(ClientProxy* client, + const std::string& service_id, + const ConnectionOptions& options, + const DiscoveryListener& listener) { + Future response; + ConnectionOptions discovery_options = options.CompatibleOptions(); + RunOnPcpHandlerThread( + [this, client, service_id, discovery_options, &listener, &response]() { + // Ask the implementation to attempt to start discovery. + auto result = StartDiscoveryImpl(client, service_id, discovery_options); + if (!result.status.Ok()) { + response.Set(result.status); + return; + } - void run() override { - base_pcp_handler_->stopAdvertisingImpl(client_proxy_); - client_proxy_->stoppedAdvertising(); - // base_pcp_handler_->advertising_options_ is purposefully not destroyed - // here. - base_pcp_handler_->advertising_connection_lifecycle_listener_.destroy(); - latch_->countDown(); - } + // Now that we've succeeded, mark the client as discovering and clear + // out any old endpoints we had discovered. + discovery_options_ = discovery_options; + discovered_endpoints_.clear(); + client->StartedDiscovery(service_id, GetStrategy(), listener, + absl::MakeSpan(result.mediums)); + response.Set({Status::kSuccess}); + }); + return WaitForResult(absl::StrCat("StartDiscovery(", service_id, ")"), + client->GetClientId(), &response); +} - private: - Ptr> base_pcp_handler_; - Ptr> client_proxy_; - Ptr latch_; -}; +void BasePcpHandler::StopDiscovery(ClientProxy* client) { + CountDownLatch latch(1); + RunOnPcpHandlerThread([this, client, &latch]() { + StopDiscoveryImpl(client); + client->StoppedDiscovery(); + discovery_options_.Clear(); + latch.CountDown(); + }); -template -class StartDiscoveryCallable : public Callable { - public: - StartDiscoveryCallable(Ptr> base_pcp_handler, - Ptr> client_proxy, - const string& service_id, - const DiscoveryOptions& options, - Ptr discovery_listener) - : base_pcp_handler_(base_pcp_handler), - client_proxy_(client_proxy), - service_id_(service_id), - options_(options), - discovery_listener_(discovery_listener) {} + WaitForLatch("StopDiscovery", &latch); +} - ExceptionOr call() override { - // Ask the implementation to attempt to start discovery. - ScopedPtr::StartOperationResult>> - result(base_pcp_handler_->startDiscoveryImpl(client_proxy_, service_id_, - options_)); - if (Status::SUCCESS != result->status_) { - return ExceptionOr(result->status_); +void BasePcpHandler::InjectEndpoint( + ClientProxy* client, const std::string& service_id, + const OutOfBandConnectionMetadata& metadata) { + CountDownLatch latch(1); + RunOnPcpHandlerThread([this, client, service_id, metadata, + &latch]() { + InjectEndpointImpl(client, service_id, metadata); + latch.CountDown(); + }); + + WaitForLatch(absl::StrCat("InjectEndpoint(", service_id, ")"), &latch); +} + +void BasePcpHandler::WaitForLatch(const std::string& method_name, + CountDownLatch* latch) { + Exception await_exception = latch->Await(); + if (!await_exception.Ok()) { + if (await_exception.Raised(Exception::kTimeout)) { + NEARBY_LOG(INFO, "Blocked in %s", method_name.c_str()); } + } +} - // Now that we've succeeded, mark the client as discovering and clear out - // any old endpoints we had discovered. - // Previous discovery_options_ is not destroyed here because stopDiscovery() - // is expected to be called before startDiscovery(). - base_pcp_handler_->discovery_options_ = - MakePtr(new DiscoveryOptions(options_)); - for (typename BasePCPHandler::DiscoveredEndpointsMap::iterator - it = base_pcp_handler_->discovered_endpoints_.begin(); - it != base_pcp_handler_->discovered_endpoints_.end(); it++) { - it->second.destroy(); - } - base_pcp_handler_->discovered_endpoints_.clear(); - client_proxy_->startedDiscovery( - service_id_, base_pcp_handler_->getStrategy(), - discovery_listener_.release(), result->mediums_); - return ExceptionOr(Status::SUCCESS); +Status BasePcpHandler::WaitForResult(const std::string& method_name, + std::int64_t client_id, + Future* future) { + if (!future) { + NEARBY_LOG(INFO, "No future to wait for; return with error"); + return {Status::kError}; + } + NEARBY_LOG(INFO, "waiting for future to complete"); + ExceptionOr result = future->Get(); + if (!result.ok()) { + NEARBY_LOG(INFO, "Future:[%s] completed with exception: %d", + method_name.c_str(), result.exception()); + return {Status::kError}; + } + NEARBY_LOG(INFO, "Future:[%s] completed with status: %d", method_name.c_str(), + result.result().value); + return result.result(); +} + +void BasePcpHandler::RunOnPcpHandlerThread(Runnable runnable) { + serial_executor_.Execute(std::move(runnable)); +} + +EncryptionRunner::ResultListener BasePcpHandler::GetResultListener() { + return { + .on_success_cb = + [this](const std::string& endpoint_id, + std::unique_ptr ukey2, + const std::string& auth_token, + const ByteArray& raw_auth_token) { + RunOnPcpHandlerThread([this, endpoint_id, + raw_ukey2 = ukey2.release(), auth_token, + raw_auth_token]() mutable { + OnEncryptionSuccessRunnable( + endpoint_id, std::unique_ptr(raw_ukey2), + auth_token, raw_auth_token); + }); + }, + .on_failure_cb = + [this](const std::string& endpoint_id, EndpointChannel* channel) { + RunOnPcpHandlerThread([this, endpoint_id, channel]() { + OnEncryptionFailureRunnable(endpoint_id, channel); + }); + }, + }; +} + +void BasePcpHandler::OnEncryptionSuccessRunnable( + const std::string& endpoint_id, std::unique_ptr ukey2, + const std::string& auth_token, const ByteArray& raw_auth_token) { + // Quick fail if we've been removed from pending connections while we were + // busy running UKEY2. + auto it = pending_connections_.find(endpoint_id); + if (it == pending_connections_.end()) { + NEARBY_LOG(INFO, + "Connection not found on UKEY negotination complete; id=%s", + endpoint_id.c_str()); + return; } - private: - Ptr> base_pcp_handler_; - Ptr> client_proxy_; - const string service_id_; - const DiscoveryOptions options_; - ScopedPtr> discovery_listener_; -}; + BasePcpHandler::PendingConnectionInfo& connection_info = it->second; -template -class StopDiscoveryRunnable : public Runnable { - public: - StopDiscoveryRunnable(Ptr> base_pcp_handler, - Ptr> client_proxy, - Ptr latch) - : base_pcp_handler_(base_pcp_handler), - client_proxy_(client_proxy), - latch_(latch) {} - - void run() override { - base_pcp_handler_->stopDiscoveryImpl(client_proxy_); - client_proxy_->stoppedDiscovery(); - // base_pcp_handler_->discovery_options_ is purposefully not destroyed here. - latch_->countDown(); + if (!ukey2) { + // Fail early, if there is no crypto context. + ProcessPreConnectionResultFailure(connection_info.client, endpoint_id); + return; } - private: - Ptr> base_pcp_handler_; - Ptr> client_proxy_; - Ptr latch_; -}; + connection_info.SetCryptoContext(std::move(ukey2)); + NEARBY_LOG(INFO, "Register encrypted connection; wait for response; id=%s", + endpoint_id.c_str()); -template -class RequestConnectionRunnable : public Runnable { - public: - RequestConnectionRunnable( - Ptr> base_pcp_handler, - Ptr> client_proxy, - const string& local_endpoint_name, const string& endpoint_id, - Ptr connection_lifecycle_listener, - Ptr> result) - : base_pcp_handler_(base_pcp_handler), - client_proxy_(client_proxy), - local_endpoint_name_(local_endpoint_name), - endpoint_id_(endpoint_id), - connection_lifecycle_listener_(connection_lifecycle_listener), - result_(result) {} + // Set ourselves up so that we receive all acceptance/rejection messages + handle_ = endpoint_manager_->RegisterFrameProcessor( + V1Frame::CONNECTION_RESPONSE, + static_cast(this)); - void run() override { - std::int64_t start_time_millis = - base_pcp_handler_->system_clock_->elapsedRealtime(); + // Now we register our endpoint so that we can listen for both sides to + // accept. + endpoint_manager_->RegisterEndpoint( + connection_info.client, endpoint_id, + { + .remote_endpoint_info = connection_info.remote_endpoint_info, + .authentication_token = auth_token, + .raw_authentication_token = raw_auth_token, + .is_incoming_connection = connection_info.is_incoming, + }, + connection_info.options, std::move(connection_info.channel), + connection_info.listener); + + if (connection_info.result != nullptr) { + NEARBY_LOG(INFO, "Connection established; Finalising future OK"); + connection_info.result->Set({Status::kSuccess}); + connection_info.result = nullptr; + } +} + +void BasePcpHandler::OnEncryptionFailureRunnable( + const std::string& endpoint_id, EndpointChannel* endpoint_channel) { + auto it = pending_connections_.find(endpoint_id); + if (it == pending_connections_.end()) { + NEARBY_LOG(INFO, + "Connection not found on UKEY negotination complete; id=%s", + endpoint_id.c_str()); + return; + } + + BasePcpHandler::PendingConnectionInfo& info = it->second; + // We had a bug here, caused by a race with EncryptionRunner. We now verify + // the EndpointChannel to avoid it. In a simultaneous connection, we clean + // up one of the two EndpointChannels and then update our pendingConnections + // with the winning channel's state. Closing a channel that was in the + // middle of EncryptionRunner would trigger onEncryptionFailed, and, since + // the map had already updated with the winning EndpointChannel, we closed + // it too by accident. + if (*endpoint_channel != *info.channel) { + NEARBY_LOG( + INFO, "Not destroying channel [mismatch]: passed=%s; expected=%s", + endpoint_channel->GetName().c_str(), info.channel->GetName().c_str()); + return; + } + + ProcessPreConnectionInitiationFailure(endpoint_id, info.channel.get(), + {Status::kEndpointIoError}, + info.result.get()); + info.result.reset(); +} + +Status BasePcpHandler::RequestConnection(ClientProxy* client, + const std::string& endpoint_id, + const ConnectionRequestInfo& info, + const ConnectionOptions& options) { + Future result; + RunOnPcpHandlerThread([this, client, &info, options, endpoint_id, &result]() { + absl::Time start_time = SystemClock::ElapsedRealtime(); // If we already have a pending connection, then we shouldn't allow any more // outgoing connections to this endpoint. - typename BasePCPHandler::PendingConnectionsMap::iterator it = - base_pcp_handler_->pending_connections_.find(endpoint_id_); - if (it != base_pcp_handler_->pending_connections_.end()) { - // TODO(tracyzhou): Add logging. - result_->set(Status::ALREADY_CONNECTED_TO_ENDPOINT); + if (pending_connections_.count(endpoint_id)) { + NEARBY_LOG(INFO, "Connection already exists: id=%s", endpoint_id.c_str()); + result.Set({Status::kAlreadyConnectedToEndpoint}); return; } // If our child class says we can't send any more outgoing connections, // listen to them. - if (base_pcp_handler_->shouldEnforceTopologyConstraints() && - !base_pcp_handler_->canSendOutgoingConnection(client_proxy_)) { - // TODO(tracyzhou): Add logging. - result_->set(Status::OUT_OF_ORDER_API_CALL); + if (ShouldEnforceTopologyConstraints() && + !CanSendOutgoingConnection(client)) { + NEARBY_LOG(INFO, "Outgoing connection not allowed: id=%s", + endpoint_id.c_str()); + result.Set({Status::kOutOfOrderApiCall}); return; } - Ptr::DiscoveredEndpoint> endpoint = - base_pcp_handler_->getDiscoveredEndpoint(endpoint_id_); - if (endpoint.isNull()) { - // TODO(tracyzhou): Add logging. - result_->set(Status::ENDPOINT_UNKNOWN); + DiscoveredEndpoint* endpoint = GetDiscoveredEndpoint(endpoint_id); + if (endpoint == nullptr) { + NEARBY_LOG(INFO, "Discovered endpoint not found: id=%s", + endpoint_id.c_str()); + result.Set({Status::kEndpointUnknown}); return; } - typename BasePCPHandler::ConnectImplResult connect_impl_result = - base_pcp_handler_->connectImpl(client_proxy_, endpoint); - - if (connect_impl_result.endpoint_channel.isNull()) { - // TODO(tracyzhou): Add logging - base_pcp_handler_->processPreConnectionInitiationFailure( - client_proxy_, connect_impl_result.medium, endpoint_id_, - connect_impl_result.endpoint_channel, false /* is_incoming */, - start_time_millis, connect_impl_result.status, result_); - return; + auto remote_bluetooth_mac_address = + BluetoothUtils::ToString(options.remote_bluetooth_mac_address); + if (!remote_bluetooth_mac_address.empty()) { + if (AppendRemoteBluetoothMacAddressEndpoint(endpoint_id, + remote_bluetooth_mac_address)) + NEARBY_LOGS(INFO) << "Appended remote Bluetooth MAC Address endpoint " + << "[" << remote_bluetooth_mac_address << "]"; } - ScopedPtr> scoped_endpoint_channel( - connect_impl_result.endpoint_channel); + if (AppendWebRTCEndpoint(endpoint_id)) + NEARBY_LOGS(INFO) << "Appended Web RTC endpoint."; - // TODO(tracyzhou): Add logging. - // Generate the nonce to use for this connection. - std::int32_t nonce = base_pcp_handler_->prng_.nextInt32(); + auto discovered_endpoints = GetDiscoveredEndpoints(endpoint_id); + std::unique_ptr channel; + ConnectImplResult connect_impl_result; - // The first message we have to send, after connecting, is to tell the - // endpoint about ourselves. - Exception::Value write_exception = - base_pcp_handler_->writeConnectionRequestFrame( - scoped_endpoint_channel.get(), - client_proxy_->generateLocalEndpointId(), local_endpoint_name_, - nonce, base_pcp_handler_->getConnectionMediumsByPriority()); - if (Exception::NONE != write_exception) { - if (Exception::IO == write_exception) { - base_pcp_handler_->processPreConnectionInitiationFailure( - client_proxy_, scoped_endpoint_channel->getMedium(), endpoint_id_, - scoped_endpoint_channel.get(), false /* is_incoming */, - start_time_millis, Status::ENDPOINT_IO_ERROR, result_); - return; + for (auto connect_endpoint : discovered_endpoints) { + connect_impl_result = ConnectImpl(client, connect_endpoint); + if (connect_impl_result.status.Ok()) { + channel = std::move(connect_impl_result.endpoint_channel); + break; } } - // TODO(tracyzhou): Add logging. + if (channel == nullptr) { + NEARBY_LOG(INFO, "Endpoint channel not available: id=%s", + endpoint_id.c_str()); + ProcessPreConnectionInitiationFailure( + endpoint_id, channel.get(), connect_impl_result.status, &result); + return; + } + + NEARBY_LOG(INFO, "Sending connection request: id=%s", endpoint_id.c_str()); + // Generate the nonce to use for this connection. + std::int32_t nonce = prng_.NextInt32(); + + // The first message we have to send, after connecting, is to tell the + // endpoint about ourselves. + Exception write_exception = WriteConnectionRequestFrame( + channel.get(), client->GetLocalEndpointId(), info.endpoint_info, nonce, + GetConnectionMediumsByPriority()); + if (!write_exception.Ok()) { + NEARBY_LOG(INFO, "Failed to send connection request: id=%s", + endpoint_id.c_str()); + ProcessPreConnectionInitiationFailure( + endpoint_id, channel.get(), {Status::kEndpointIoError}, &result); + return; + } + + NEARBY_LOG(INFO, "adding connection to pending set: id=%s", + endpoint_id.c_str()); // We've successfully connected to the device, and are now about to jump on // to the EncryptionRunner thread to start running our encryption protocol. // We'll mark ourselves as pending in case we get another call to - // requestConnection or onIncomingConnection, so that we can cancel the + // RequestConnection or OnIncomingConnection, so that we can cancel the // connection if needed. - Ptr endpoint_channel = - base_pcp_handler_->pending_connections_ - .insert(std::make_pair( - endpoint_id_, - BasePCPHandler::PendingConnectionInfo:: - newOutgoingPendingConnectionInfo( - client_proxy_, endpoint->getEndpointName(), - scoped_endpoint_channel.release(), nonce, - start_time_millis, - connection_lifecycle_listener_.release(), result_))) - .first->second->endpoint_channel_.get(); + EndpointChannel* endpoint_channel = + pending_connections_ + .emplace(endpoint_id, + PendingConnectionInfo{ + .client = client, + .remote_endpoint_info = endpoint->endpoint_info, + .nonce = nonce, + .is_incoming = false, + .start_time = start_time, + .listener = info.listener, + .options = options, + .result = MakeSwapper(&result), + .channel = std::move(channel), + }) + .first->second.channel.get(); + NEARBY_LOG(INFO, "Initiating secure connection: id=%s", + endpoint_id.c_str()); // Next, we'll set up encryption. When it's done, our future will return and - // requestConnection() will finish. - base_pcp_handler_->encryption_runner_->startClient( - client_proxy_, endpoint_id_, endpoint_channel, - MakePtr(new typename BasePCPHandler::ResultListenerFacade( - base_pcp_handler_))); + // RequestConnection() will finish. + encryption_runner_.StartClient(client, endpoint_id, endpoint_channel, + GetResultListener()); + }); + NEARBY_LOG(INFO, "Waiting for connection to complete: id=%s", + endpoint_id.c_str()); + auto status = + WaitForResult(absl::StrCat("RequestConnection(", endpoint_id, ")"), + client->GetClientId(), &result); + NEARBY_LOG(INFO, "Wait is complete: id=%s; status=%d", endpoint_id.c_str(), + status.value); + return status; +} + +// Get any single discovered endpoint for a given endpoint_id. +BasePcpHandler::DiscoveredEndpoint* BasePcpHandler::GetDiscoveredEndpoint( + const std::string& endpoint_id) { + auto it = discovered_endpoints_.find(endpoint_id); + if (it == discovered_endpoints_.end()) { + return nullptr; + } + return it->second.get(); +} + +std::vector +BasePcpHandler::GetDiscoveredEndpoints(const std::string& endpoint_id) { + std::vector result; + auto it = discovered_endpoints_.equal_range(endpoint_id); + for (auto item = it.first; item != it.second; item++) { + result.push_back(item->second.get()); + } + std::sort(result.begin(), result.end(), + [this](DiscoveredEndpoint* a, DiscoveredEndpoint* b) -> bool { + return IsPreferred(*a, *b); + }); + return result; +} + +void BasePcpHandler::PendingConnectionInfo::SetCryptoContext( + std::unique_ptr ukey2) { + this->ukey2 = std::move(ukey2); +} + +bool BasePcpHandler::HasOutgoingConnections(ClientProxy* client) const { + for (const auto& item : pending_connections_) { + auto& connection = item.second; + if (!connection.is_incoming) { + return true; + } + } + return client->GetNumOutgoingConnections() > 0; +} + +bool BasePcpHandler::HasIncomingConnections(ClientProxy* client) const { + for (const auto& item : pending_connections_) { + auto& connection = item.second; + if (connection.is_incoming) { + return true; + } + } + return client->GetNumIncomingConnections() > 0; +} + +bool BasePcpHandler::CanSendOutgoingConnection(ClientProxy* client) const { + return true; +} + +bool BasePcpHandler::CanReceiveIncomingConnection(ClientProxy* client) const { + return true; +} + +Exception BasePcpHandler::WriteConnectionRequestFrame( + EndpointChannel* endpoint_channel, const std::string& local_endpoint_id, + const ByteArray& local_endpoint_info, std::int32_t nonce, + const std::vector& supported_mediums) { + return endpoint_channel->Write(parser::ForConnectionRequest( + local_endpoint_id, local_endpoint_info, nonce, supported_mediums)); +} + +void BasePcpHandler::ProcessPreConnectionInitiationFailure( + const std::string& endpoint_id, EndpointChannel* channel, Status status, + Future* result) { + if (channel != nullptr) { + channel->Close(); } - private: - Ptr> base_pcp_handler_; - Ptr> client_proxy_; - const string local_endpoint_name_; - const string endpoint_id_; - ScopedPtr> connection_lifecycle_listener_; - Ptr> result_; -}; + pending_connections_.erase(endpoint_id); -template -class AcceptConnectionCallable : public Callable { - public: - AcceptConnectionCallable(Ptr> base_pcp_handler, - Ptr> client_proxy, - const string& endpoint_id, - Ptr payload_listener) - : base_pcp_handler_(base_pcp_handler), - client_proxy_(client_proxy), - endpoint_id_(endpoint_id), - payload_listener_(payload_listener) {} + if (result != nullptr) { + NEARBY_LOG(INFO, "Connection failed; aborting future"); + result->Set(status); + } +} - ExceptionOr call() override { - // TODO(tracyzhou): Add logging. - typename BasePCPHandler::PendingConnectionsMap::iterator it = - base_pcp_handler_->pending_connections_.find(endpoint_id_); - if (it == base_pcp_handler_->pending_connections_.end()) { - // TODO(tracyzhou): Add logging. - return ExceptionOr(Status::ENDPOINT_UNKNOWN); +void BasePcpHandler::ProcessPreConnectionResultFailure( + ClientProxy* client, const std::string& endpoint_id) { + auto item = pending_connections_.extract(endpoint_id); + endpoint_manager_->DiscardEndpoint(client, endpoint_id); + client->OnConnectionRejected(endpoint_id, {Status::kError}); +} + +bool BasePcpHandler::ShouldEnforceTopologyConstraints() const { + // Topology constraints only matter for the advertiser. + // For discoverers, we'll always enforce them. + if (advertising_options_.strategy.IsNone()) { + return true; + } + + return advertising_options_.enforce_topology_constraints; +} + +bool BasePcpHandler::AutoUpgradeBandwidth() const { + if (advertising_options_.strategy.IsNone()) { + return true; + } + + return advertising_options_.auto_upgrade_bandwidth; +} + +Status BasePcpHandler::AcceptConnection( + ClientProxy* client, const std::string& endpoint_id, + const PayloadListener& payload_listener) { + Future response; + RunOnPcpHandlerThread( + [this, client, endpoint_id, payload_listener, &response]() { + NEARBY_LOG(INFO, "AcceptConnection: id=%s", endpoint_id.c_str()); + if (!pending_connections_.count(endpoint_id)) { + NEARBY_LOG(INFO, "AcceptConnection: no pending connection for id=%s", + endpoint_id.c_str()); + response.Set({Status::kEndpointUnknown}); + return; + } + auto& connection_info = pending_connections_[endpoint_id]; + + // By this point in the flow, connection_info.channel has been + // nulled out because ownership of that EndpointChannel was passed on to + // EndpointChannelManager via a call to + // EndpointManager::registerEndpoint(), so we now need to get access to + // the EndpointChannel from the authoritative owner. + std::shared_ptr channel = + channel_manager_->GetChannelForEndpoint(endpoint_id); + if (channel == nullptr) { + NEARBY_LOG( + ERROR, + "Channel destroyed before Accept; bring down connection: id=%s", + endpoint_id.c_str()); + ProcessPreConnectionResultFailure(client, endpoint_id); + response.Set({Status::kEndpointUnknown}); + return; + } + + Exception write_exception = + channel->Write(parser::ForConnectionResponse(Status::kSuccess)); + if (!write_exception.Ok()) { + NEARBY_LOG(INFO, "AcceptConnection: failed to send response: id=%s", + endpoint_id.c_str()); + ProcessPreConnectionResultFailure(client, endpoint_id); + response.Set({Status::kEndpointIoError}); + return; + } + + NEARBY_LOG(INFO, "AcceptConnection: accepting locally: id=%s", + endpoint_id.c_str()); + connection_info.LocalEndpointAcceptedConnection(endpoint_id, + payload_listener); + EvaluateConnectionResult(client, endpoint_id, + false /* can_close_immediately */); + response.Set({Status::kSuccess}); + }); + + return WaitForResult(absl::StrCat("AcceptConnection(", endpoint_id, ")"), + client->GetClientId(), &response); +} + +Status BasePcpHandler::RejectConnection(ClientProxy* client, + const std::string& endpoint_id) { + Future response; + RunOnPcpHandlerThread([this, client, endpoint_id, &response]() { + NEARBY_LOG(INFO, "RejectConnection: id=%s", endpoint_id.c_str()); + if (!pending_connections_.count(endpoint_id)) { + NEARBY_LOG(INFO, "RejectConnection: no pending connection for id=%s", + endpoint_id.c_str()); + response.Set({Status::kEndpointUnknown}); + return; } - Ptr::PendingConnectionInfo> - connection_info = it->second; + auto& connection_info = pending_connections_[endpoint_id]; // By this point in the flow, connection_info->endpoint_channel_ has been // nulled out because ownership of that EndpointChannel was passed on to // EndpointChannelManager via a call to // EndpointManager::registerEndpoint(), so we now need to get access to the // EndpointChannel from the authoritative owner. - ScopedPtr> scoped_endpoint_channel( - base_pcp_handler_->endpoint_channel_manager_->getChannelForEndpoint( - endpoint_id_)); - if (scoped_endpoint_channel.isNull()) { - // TODO(reznor): Add logging. - base_pcp_handler_->processPreConnectionResultFailure(client_proxy_, - endpoint_id_); - return ExceptionOr(Status::ENDPOINT_UNKNOWN); + std::shared_ptr channel = + channel_manager_->GetChannelForEndpoint(endpoint_id); + if (channel == nullptr) { + NEARBY_LOG( + ERROR, + "Channel destroyed before Reject; bring down connection: id=%s", + endpoint_id.c_str()); + ProcessPreConnectionResultFailure(client, endpoint_id); + response.Set({Status::kEndpointUnknown}); + return; } - Exception::Value write_exception = scoped_endpoint_channel->write( - OfflineFrames::forConnectionResponse(Status::SUCCESS)); - if (Exception::NONE != write_exception) { - if (Exception::IO == write_exception) { - // TODO(tracyzhou): Add logging. - base_pcp_handler_->processPreConnectionResultFailure(client_proxy_, - endpoint_id_); - return ExceptionOr(Status::ENDPOINT_IO_ERROR); - } + Exception write_exception = channel->Write( + parser::ForConnectionResponse(Status::kConnectionRejected)); + if (!write_exception.Ok()) { + NEARBY_LOG(INFO, "RejectConnection: failed to send response: id=%s", + endpoint_id.c_str()); + ProcessPreConnectionResultFailure(client, endpoint_id); + response.Set({Status::kEndpointIoError}); + return; } - // TODO(tracyzhou): Add logging. - connection_info->localEndpointAcceptedConnection( - endpoint_id_, payload_listener_.release()); - base_pcp_handler_->evaluateConnectionResult( - client_proxy_, endpoint_id_, false /* can_close_immediately */); - return ExceptionOr(Status::SUCCESS); - } + NEARBY_LOG(INFO, "RejectConnection: rejecting locally: id=%s", + endpoint_id.c_str()); + connection_info.LocalEndpointRejectedConnection(endpoint_id); + EvaluateConnectionResult(client, endpoint_id, + false /* can_close_immediately */); + response.Set({Status::kSuccess}); + }); - private: - Ptr> base_pcp_handler_; - Ptr> client_proxy_; - const string endpoint_id_; - ScopedPtr> payload_listener_; -}; + return WaitForResult(absl::StrCat("RejectConnection(", endpoint_id, ")"), + client->GetClientId(), &response); +} -template -class RejectConnectionCallable : public Callable { - public: - RejectConnectionCallable(Ptr> base_pcp_handler, - Ptr> client_proxy, - const string& endpoint_id) - : base_pcp_handler_(base_pcp_handler), - client_proxy_(client_proxy), - endpoint_id_(endpoint_id) {} +void BasePcpHandler::OnIncomingFrame(OfflineFrame& frame, + const std::string& endpoint_id, + ClientProxy* client, + proto::connections::Medium medium) { + CountDownLatch latch(1); + RunOnPcpHandlerThread([this, client, endpoint_id, frame, &latch]() { + NEARBY_LOG(INFO, "OnConnectionResponse: id=%s", endpoint_id.c_str()); - ExceptionOr call() override { - // TODO(tracyzhou): Add logging. - typename BasePCPHandler::PendingConnectionsMap::iterator it = - base_pcp_handler_->pending_connections_.find(endpoint_id_); - if (it == base_pcp_handler_->pending_connections_.end()) { - // TODO(tracyzhou): Add logging. - return ExceptionOr(Status::ENDPOINT_UNKNOWN); - } - Ptr::PendingConnectionInfo> - connection_info = it->second; - - // By this point in the flow, connection_info->endpoint_channel_ has been - // nulled out because ownership of that EndpointChannel was passed on to - // EndpointChannelManager via a call to - // EndpointManager::registerEndpoint(), so we now need to get access to the - // EndpointChannel from the authoritative owner. - ScopedPtr> scoped_endpoint_channel( - base_pcp_handler_->endpoint_channel_manager_->getChannelForEndpoint( - endpoint_id_)); - if (scoped_endpoint_channel.isNull()) { - // TODO(reznor): Add logging. - base_pcp_handler_->processPreConnectionResultFailure(client_proxy_, - endpoint_id_); - return ExceptionOr(Status::ENDPOINT_UNKNOWN); - } - - Exception::Value write_exception = scoped_endpoint_channel->write( - OfflineFrames::forConnectionResponse(Status::CONNECTION_REJECTED)); - if (Exception::NONE != write_exception) { - if (Exception::IO == write_exception) { - // TODO(tracyzhou): Add logging. - base_pcp_handler_->processPreConnectionResultFailure(client_proxy_, - endpoint_id_); - return ExceptionOr(Status::ENDPOINT_IO_ERROR); - } - } - - // TODO(tracyzhou): Add logging. - connection_info->localEndpointRejectedConnection(endpoint_id_); - base_pcp_handler_->evaluateConnectionResult( - client_proxy_, endpoint_id_, false /* can_close_immediately */); - return ExceptionOr(Status::SUCCESS); - } - - private: - Ptr> base_pcp_handler_; - Ptr> client_proxy_; - const string endpoint_id_; -}; - -class ReadConnectionRequestCancelableAlarmRunnable : public Runnable { - public: - explicit ReadConnectionRequestCancelableAlarmRunnable( - Ptr endpoint_channel) - : endpoint_channel_(endpoint_channel) {} - - void run() override { - // TODO(tracyzhou): Add logging. - endpoint_channel_->close(); - } - - private: - Ptr endpoint_channel_; -}; - -template -class EvaluateConnectionResultCancelableAlarmRunnable : public Runnable { - public: - EvaluateConnectionResultCancelableAlarmRunnable( - Ptr> endpoint_manager, - Ptr> client_proxy, const string& endpoint_id) - : endpoint_manager_(endpoint_manager), - client_proxy_(client_proxy), - endpoint_id_(endpoint_id) {} - - void run() override { - // TODO(tracyzhou): Add logging. - endpoint_manager_->discardEndpoint(client_proxy_, endpoint_id_); - } - - private: - Ptr> endpoint_manager_; - Ptr> client_proxy_; - const string endpoint_id_; -}; - -template -class ProcessEndpointDisconnectionRunnable : public Runnable { - public: - ProcessEndpointDisconnectionRunnable( - Ptr> base_pcp_handler, - Ptr> client_proxy, const string& endpoint_id, - Ptr process_disconnection_barrier) - : base_pcp_handler_(base_pcp_handler), - client_proxy_(client_proxy), - endpoint_id_(endpoint_id), - process_disconnection_barrier_(process_disconnection_barrier) {} - - void run() override { - typename BasePCPHandler< - Platform>::PendingRejectedConnectionCloseAlarmsMap::iterator it = - base_pcp_handler_->pending_rejected_connection_close_alarms_.find( - endpoint_id_); - if (it != - base_pcp_handler_->pending_rejected_connection_close_alarms_.end()) { - it->second->cancel(); - it->second.destroy(); - base_pcp_handler_->pending_rejected_connection_close_alarms_.erase(it); - } - base_pcp_handler_->processPreConnectionResultFailure(client_proxy_, - endpoint_id_); - - process_disconnection_barrier_->countDown(); - } - - private: - Ptr> base_pcp_handler_; - Ptr> client_proxy_; - const string endpoint_id_; - Ptr process_disconnection_barrier_; -}; - -template -class OnConnectionResponseRunnable : public Runnable { - public: - OnConnectionResponseRunnable(Ptr> base_pcp_handler, - Ptr> client_proxy, - const string& endpoint_id, - ConstPtr offline_frame, - Ptr latch) - : base_pcp_handler_(base_pcp_handler), - client_proxy_(client_proxy), - endpoint_id_(endpoint_id), - offline_frame_(offline_frame), - latch_(latch) {} - - void run() override { - // TODO(tracyzhou): Add logging. - - if (client_proxy_->hasRemoteEndpointResponded(endpoint_id_)) { - // TODO(tracyzhou): Add logging. + if (client->HasRemoteEndpointResponded(endpoint_id)) { + NEARBY_LOG(INFO, "OnConnectionResponse: already handled; id=%s", + endpoint_id.c_str()); return; } const ConnectionResponseFrame& connection_response = - offline_frame_->v1().connection_response(); + frame.v1().connection_response(); - // TODO(tracyzhou): Assign int values to Status. - if (Status::SUCCESS == connection_response.status()) { - // TODO(tracyzhou): Add logging. - client_proxy_->remoteEndpointAcceptedConnection(endpoint_id_); + // For backward compatible, here still check both status and + // response parameters until the response feature is roll out in all + // supported devices. + bool accepted = false; + if (connection_response.has_response()) { + accepted = + connection_response.response() == ConnectionResponseFrame::ACCEPT; } else { - // TODO(tracyzhou): Add logging. - client_proxy_->remoteEndpointRejectedConnection(endpoint_id_); + accepted = connection_response.status() == Status::kSuccess; + } + if (accepted) { + NEARBY_LOG(INFO, "OnConnectionResponse: remote accepted; id=%s", + endpoint_id.c_str()); + client->RemoteEndpointAcceptedConnection(endpoint_id); + } else { + NEARBY_LOG(INFO, + "OnConnectionResponse: remote rejected; id=%s; status=%d", + endpoint_id.c_str(), connection_response.status()); + client->RemoteEndpointRejectedConnection(endpoint_id); } - base_pcp_handler_->evaluateConnectionResult( - client_proxy_, endpoint_id_, - /* can_close_immediately= */ true); + EvaluateConnectionResult(client, endpoint_id, + /* can_close_immediately= */ true); - latch_->countDown(); + latch.CountDown(); + }); + WaitForLatch("OnIncomingFrame()", &latch); +} + +void BasePcpHandler::OnEndpointDisconnect(ClientProxy* client, + const std::string& endpoint_id, + CountDownLatch* barrier) { + if (stop_.Get()) { + if (barrier) barrier->CountDown(); + return; } - - private: - Ptr> base_pcp_handler_; - Ptr> client_proxy_; - const string endpoint_id_; - ScopedPtr> offline_frame_; - Ptr latch_; -}; - -template -class OnEncryptionSuccessRunnable : public Runnable { - public: - OnEncryptionSuccessRunnable(Ptr> base_pcp_handler, - const string& endpoint_id, - Ptr ukey2_handshake, - const string& authentication_token, - ConstPtr raw_authentication_token) - : base_pcp_handler_(base_pcp_handler), - endpoint_id_(endpoint_id), - ukey2_handshake_(ukey2_handshake), - authentication_token_(authentication_token), - raw_authentication_token_(raw_authentication_token) {} - - void run() override { - // Quick fail if we've been removed from pending connections while we were - // busy running UKEY2. - typename BasePCPHandler::PendingConnectionsMap::iterator it = - base_pcp_handler_->pending_connections_.find(endpoint_id_); - if (it == base_pcp_handler_->pending_connections_.end()) { - // TODO(tracyzhou): Add logging. - return; + RunOnPcpHandlerThread([this, client, endpoint_id, barrier]() { + auto item = pending_alarms_.find(endpoint_id); + if (item != pending_alarms_.end()) { + auto& alarm = item->second; + alarm.Cancel(); + pending_alarms_.erase(item); } - - Ptr::PendingConnectionInfo> - connection_info = it->second; - connection_info->setUKey2Handshake(ukey2_handshake_.release()); - // TODO(tracyzhou): Add logging. - - // Set ourselves up so that we receive all acceptance/rejection messages - base_pcp_handler_->endpoint_manager_->registerIncomingOfflineFrameProcessor( - V1Frame::CONNECTION_RESPONSE, base_pcp_handler_); - - // Now we register our endpoint so that we can listen for both sides to - // accept. - base_pcp_handler_->endpoint_manager_->registerEndpoint( - connection_info->client_proxy_, endpoint_id_, - connection_info->remote_endpoint_name_, authentication_token_, - raw_authentication_token_.release(), connection_info->is_incoming_, - connection_info->endpoint_channel_.release(), - connection_info->connection_lifecycle_listener_.release()); - - if (!connection_info->request_connection_result_.isNull()) { - connection_info->request_connection_result_->set(Status::SUCCESS); - connection_info->request_connection_result_.clear(); - } - } - - private: - Ptr> base_pcp_handler_; - const string endpoint_id_; - ScopedPtr> ukey2_handshake_; - const string authentication_token_; - ScopedPtr> raw_authentication_token_; -}; - -template -class OnEncryptionFailureRunnable : public Runnable { - public: - OnEncryptionFailureRunnable(Ptr> base_pcp_handler, - const string& endpoint_id, - Ptr endpoint_channel) - : base_pcp_handler_(base_pcp_handler), - endpoint_id_(endpoint_id), - endpoint_channel_(endpoint_channel) {} - - void run() override { - typename BasePCPHandler::PendingConnectionsMap::iterator it = - base_pcp_handler_->pending_connections_.find(endpoint_id_); - if (it == base_pcp_handler_->pending_connections_.end()) { - // TODO(tracyzhou): Add logging. - return; - } - - Ptr::PendingConnectionInfo> - connection_info = it->second; - // We had a bug here, caused by a race with EncryptionRunner. We now verify - // the EndpointChannel to avoid it. In a simultaneous connection, we clean - // up one of the two EndpointChannels and then update our pendingConnections - // with the winning channel's state. Closing a channel that was in the - // middle of EncryptionRunner would trigger onEncryptionFailed, and, since - // the map had already updated with the winning EndpointChannel, we closed - // it too by accident. - if (!endpointChannelsAreEqual(endpoint_channel_, - connection_info->endpoint_channel_.get())) { - // TODO(tracyzhou): Add logging. - return; - } - - base_pcp_handler_->processPreConnectionInitiationFailure( - connection_info->client_proxy_, - connection_info->endpoint_channel_->getMedium(), endpoint_id_, - connection_info->endpoint_channel_.get(), connection_info->is_incoming_, - connection_info->start_time_millis_, Status::ENDPOINT_IO_ERROR, - connection_info->request_connection_result_); - connection_info->request_connection_result_.clear(); - } - - private: - static bool endpointChannelsAreEqual(Ptr lhs, - Ptr rhs) { - return (lhs->getType() == rhs->getType()) && - (lhs->getName() == rhs->getName()) && - (lhs->getMedium() == rhs->getMedium()); - } - - Ptr> base_pcp_handler_; - const string endpoint_id_; - Ptr endpoint_channel_; -}; - -} // namespace base_pcp_handler - -template -const std::int64_t - BasePCPHandler::kConnectionRequestReadTimeoutMillis = - 2 * 1000; // 2 seconds -template -const std::int64_t - BasePCPHandler::kRejectedConnectionCloseDelayMillis = - 2 * 1000; // 2 seconds - -template -BasePCPHandler::BasePCPHandler( - Ptr> endpoint_manager, - Ptr endpoint_channel_manager, - Ptr bandwidth_upgrade_manager) - : endpoint_manager_(endpoint_manager), - endpoint_channel_manager_(endpoint_channel_manager), - bandwidth_upgrade_manager_(bandwidth_upgrade_manager), - bandwidth_upgrade_medium_(Platform::createAtomicReference( - proto::connections::Medium::UNKNOWN_MEDIUM)), - alarm_executor_(Platform::createScheduledExecutor()), - serial_executor_(Platform::createSingleThreadExecutor()), - system_clock_(Platform::createSystemClock()), - prng_(), - pending_connections_(), - discovered_endpoints_(), - pending_rejected_connection_close_alarms_(), - advertising_options_(), - discovery_options_(), - encryption_runner_(MakePtr(new EncryptionRunner())) {} - -template -BasePCPHandler::~BasePCPHandler() { - // TODO(reznor): - // logger.atDebug().log("Initiating shutdown of PCPHandler(%s).", - // getStrategy().getName()); - - // Unregister ourselves from the IncomingOfflineFrameProcessors. - endpoint_manager_->unregisterIncomingOfflineFrameProcessor( - V1Frame::CONNECTION_RESPONSE, - std::static_pointer_cast< - typename EndpointManager::IncomingOfflineFrameProcessor>( - self_)); - - encryption_runner_.destroy(); - - // Stop all the ongoing Runnables (as gracefully as possible). - serial_executor_->shutdown(); - alarm_executor_->shutdown(); - - // With the alarmExecutor shut down already, we can safely clear out our - // pending alarms. - for (typename PendingRejectedConnectionCloseAlarmsMap::iterator it = - pending_rejected_connection_close_alarms_.begin(); - it != pending_rejected_connection_close_alarms_.end(); it++) { - it->second.destroy(); - } - pending_rejected_connection_close_alarms_.clear(); - - for (typename DiscoveredEndpointsMap::iterator it = - discovered_endpoints_.begin(); - it != discovered_endpoints_.end(); it++) { - it->second.destroy(); - } - discovered_endpoints_.clear(); - - // Unblock all Futures that were stored in our pendingConnections. - for (typename PendingConnectionsMap::iterator it = - pending_connections_.begin(); - it != pending_connections_.end(); it++) { - it->second.destroy(); - } - pending_connections_.clear(); - - // TODO(reznor): - // logger.atVerbose().log("PCPHandler(%s) has shut down.", - // getStrategy().getName()); + ProcessPreConnectionResultFailure(client, endpoint_id); + barrier->CountDown(); + }); } -template -Status::Value BasePCPHandler::startAdvertising( - Ptr> client_proxy, const string& service_id, - const string& local_endpoint_name, - const AdvertisingOptions& advertising_options, - Ptr connection_lifecycle_listener) { - ScopedPtr>> result( - runOnPCPHandlerThread( - MakePtr(new base_pcp_handler::StartAdvertisingCallable( - self_, client_proxy, service_id, local_endpoint_name, - advertising_options, connection_lifecycle_listener)))); - return waitForResult("startAdvertising(" + local_endpoint_name + ")", - client_proxy->getClientId(), result.get()); +BluetoothDevice BasePcpHandler::GetRemoteBluetoothDevice( + const std::string& remote_bluetooth_mac_address) { + return mediums_->GetBluetoothClassic().GetRemoteDevice( + remote_bluetooth_mac_address); } -template -void BasePCPHandler::stopAdvertising( - Ptr> client_proxy) { - ScopedPtr> latch(Platform::createCountDownLatch(1)); - runOnPCPHandlerThread( - MakePtr(new base_pcp_handler::StopAdvertisingRunnable( - self_, client_proxy, latch.get()))); - waitForLatch("stopAdvertising", latch.get()); -} - -template -Status::Value BasePCPHandler::startDiscovery( - Ptr> client_proxy, const string& service_id, - const DiscoveryOptions& discovery_options, - Ptr discovery_listener) { - ScopedPtr>> result( - runOnPCPHandlerThread( - MakePtr(new base_pcp_handler::StartDiscoveryCallable( - self_, client_proxy, service_id, discovery_options, - discovery_listener)))); - return waitForResult("startDiscovery(" + service_id + ")", - client_proxy->getClientId(), result.get()); -} - -template -void BasePCPHandler::stopDiscovery( - Ptr> client_proxy) { - ScopedPtr> latch(Platform::createCountDownLatch(1)); - runOnPCPHandlerThread( - MakePtr(new base_pcp_handler::StopDiscoveryRunnable( - self_, client_proxy, latch.get()))); - waitForLatch("stopDiscovery", latch.get()); -} - -template -Status::Value BasePCPHandler::requestConnection( - Ptr> client_proxy, const string& local_endpoint_name, - const string& endpoint_id, - Ptr connection_lifecycle_listener) { - ScopedPtr>> result( - Platform::template createSettableFuture()); - runOnPCPHandlerThread( - MakePtr(new base_pcp_handler::RequestConnectionRunnable( - self_, client_proxy, local_endpoint_name, endpoint_id, - connection_lifecycle_listener, result.get()))); - return waitForResult("requestConnection(" + endpoint_id + ")", - client_proxy->getClientId(), result.get()); -} - -template -Status::Value BasePCPHandler::acceptConnection( - Ptr> client_proxy, const string& endpoint_id, - Ptr payload_listener) { - ScopedPtr>> result( - runOnPCPHandlerThread( - MakePtr(new base_pcp_handler::AcceptConnectionCallable( - self_, client_proxy, endpoint_id, payload_listener)))); - return waitForResult("acceptConnection(" + endpoint_id + ")", - client_proxy->getClientId(), result.get()); -} - -template -Status::Value BasePCPHandler::rejectConnection( - Ptr> client_proxy, const string& endpoint_id) { - ScopedPtr>> result( - runOnPCPHandlerThread( - MakePtr(new base_pcp_handler::RejectConnectionCallable( - self_, client_proxy, endpoint_id)))); - return waitForResult("rejectConnection(" + endpoint_id + ")", - client_proxy->getClientId(), result.get()); -} - -template -proto::connections::Medium -BasePCPHandler::getBandwidthUpgradeMedium() { - return bandwidth_upgrade_medium_->get(); -} - -template -void BasePCPHandler::processIncomingOfflineFrame( - ConstPtr offline_frame, const string& from_endpoint_id, - Ptr> to_client_proxy, - proto::connections::Medium current_medium) { - onConnectionResponse(to_client_proxy, from_endpoint_id, offline_frame); -} - -template -void BasePCPHandler::processEndpointDisconnection( - Ptr> client_proxy, const string& endpoint_id, - Ptr process_disconnection_barrier) { - runOnPCPHandlerThread(MakePtr( - new base_pcp_handler::ProcessEndpointDisconnectionRunnable( - self_, client_proxy, endpoint_id, process_disconnection_barrier))); -} - -template -void BasePCPHandler::onEncryptionSuccessImpl( - const string& endpoint_id, Ptr ukey2_handshake, - const string& authentication_token, - ConstPtr raw_authentication_token) { - runOnPCPHandlerThread( - MakePtr(new base_pcp_handler::OnEncryptionSuccessRunnable( - self_, endpoint_id, ukey2_handshake, authentication_token, - raw_authentication_token))); -} - -template -void BasePCPHandler::onEncryptionFailureImpl( - const string& endpoint_id, Ptr channel) { - runOnPCPHandlerThread( - MakePtr(new base_pcp_handler::OnEncryptionFailureRunnable( - self_, endpoint_id, channel))); -} - -template -void BasePCPHandler::runOnPCPHandlerThread(Ptr runnable) { - serial_executor_->execute(runnable); -} - -template -Ptr BasePCPHandler::getAdvertisingOptions() { +ConnectionOptions BasePcpHandler::GetConnectionOptions() const { return advertising_options_; } -template -void BasePCPHandler::onEndpointFound( - Ptr> client_proxy, - Ptr::DiscoveredEndpoint> endpoint) { - ScopedPtr::DiscoveredEndpoint>> - scoped_endpoint(endpoint); +ConnectionOptions BasePcpHandler::GetDiscoveryOptions() const { + return discovery_options_; +} +void BasePcpHandler::OnEndpointFound( + ClientProxy* client, std::shared_ptr endpoint) { // Check if we've seen this endpoint ID before. - Ptr::DiscoveredEndpoint> - previously_discovered_endpoint = - getDiscoveredEndpoint(scoped_endpoint->getEndpointId()); + std::string& endpoint_id = endpoint->endpoint_id; + NEARBY_LOG(INFO, "OnEndpointFound: id='%s' [enter]", endpoint_id.c_str()); - if (previously_discovered_endpoint.isNull()) { - const string endpoint_id = scoped_endpoint->getEndpointId(); - const string service_id = scoped_endpoint->getServiceId(); - const string endpoint_name = scoped_endpoint->getEndpointName(); - const proto::connections::Medium medium = scoped_endpoint->getMedium(); + auto range = discovered_endpoints_.equal_range(endpoint->endpoint_id); - // If this is the first medium we've discovered this endpoint over, then add - // it to the map. - discovered_endpoints_.insert( - std::make_pair(endpoint_id, scoped_endpoint.release())); + DiscoveredEndpoint* owned_endpoint = nullptr; + for (auto& item = range.first; item != range.second; ++item) { + auto& discovered_endpoint = item->second; + if (discovered_endpoint->medium != endpoint->medium) continue; + // Check if there was a info change. If there was, report the previous + // endpoint as lost. + if (discovered_endpoint->endpoint_info != endpoint->endpoint_info) { + OnEndpointLost(client, *discovered_endpoint); + discovered_endpoint = endpoint; // Replace endpoint. + OnEndpointFound(client, std::move(endpoint)); + return; + } else { + owned_endpoint = endpoint.get(); + break; + } + } + if (!owned_endpoint) { + owned_endpoint = + discovered_endpoints_.emplace(endpoint_id, std::move(endpoint)) + ->second.get(); + } + + // Range is empty: this is the first endpoint we discovered so far. + // Report this endpoint_id to client. + if (range.first == range.second) { + NEARBY_LOG(INFO, "Adding new endpoint: id=%s", endpoint_id.c_str()); // And, as it's the first time, report it to the client. - client_proxy->onEndpointFound(endpoint_id, service_id, endpoint_name, - medium); - } else if (previously_discovered_endpoint->getEndpointName() != - scoped_endpoint->getEndpointName()) { - // If we've already seen this endpoint before, check if there was a name - // change. If there was, report the previous endpoint as lost. - // TODO(tracyzhou): Add logging. - onEndpointLost(client_proxy, previously_discovered_endpoint); - onEndpointFound(client_proxy, scoped_endpoint.release()); + client->OnEndpointFound( + owned_endpoint->service_id, owned_endpoint->endpoint_id, + owned_endpoint->endpoint_info, owned_endpoint->medium); } else { - // Otherwise, we need to see if the medium we discovered the endpoint over - // this time is better than the medium we originally discovered the endpoint - // over. - if (isPreferred(scoped_endpoint.get(), previously_discovered_endpoint)) { - base_pcp_handler::eraseOwnedPtrFromMap(discovered_endpoints_, - scoped_endpoint->getEndpointId()); - discovered_endpoints_.insert(std::make_pair( - scoped_endpoint->getEndpointId(), scoped_endpoint.release())); - } + NEARBY_LOGS(INFO) << "Adding new medium for endpoint: id=" << endpoint_id + << "; medium=" << owned_endpoint->medium; } } -template -void BasePCPHandler::onEndpointLost( - Ptr> client_proxy, - Ptr::DiscoveredEndpoint> endpoint) { - ScopedPtr::DiscoveredEndpoint>> - scoped_endpoint(endpoint); - +void BasePcpHandler::OnEndpointLost( + ClientProxy* client, const BasePcpHandler::DiscoveredEndpoint& endpoint) { // Look up the DiscoveredEndpoint we have in our cache. - Ptr::DiscoveredEndpoint> - discoveredEndpoint = - getDiscoveredEndpoint(scoped_endpoint->getEndpointId()); - if (discoveredEndpoint.isNull()) { - // TODO(tracyzhou): Add logging. + const auto* discovered_endpoint = GetDiscoveredEndpoint(endpoint.endpoint_id); + if (discovered_endpoint == nullptr) { + NEARBY_LOG(INFO, "No previous endpoint (nothing to lose): id=%s", + endpoint.endpoint_id.c_str()); return; } - // Validate that the cached endpoint has the same name as the one reported as - // onLost. If the name differs, then no-op. This likely means that the remote - // device changed their name. We reported onFound for the new name and are - // just now figuring out that we lost the old name. - if (discoveredEndpoint->getEndpointName() != - scoped_endpoint->getEndpointName()) { - // TODO(tracyzhou): Add logging. + // Validate that the cached endpoint has the same info as the one reported as + // onLost. If the info differs, then no-op. This likely means that the remote + // device changed their info. We reported onFound for the new info and are + // just now figuring out that we lost the old info. + if (discovered_endpoint->endpoint_info != endpoint.endpoint_info) { + NEARBY_LOG(INFO, "Previous endpoint name mismatch; passed=%s; expected=%s", + absl::BytesToHexString(endpoint.endpoint_info.data()).c_str(), + absl::BytesToHexString(discovered_endpoint->endpoint_info.data()) + .c_str()); return; } - base_pcp_handler::eraseOwnedPtrFromMap(discovered_endpoints_, - scoped_endpoint->getEndpointId()); - client_proxy->onEndpointLost(scoped_endpoint->getServiceId(), - scoped_endpoint->getEndpointId()); -} - -template -bool BasePCPHandler::hasOutgoingConnections( - Ptr> client_proxy) { - for (typename PendingConnectionsMap::iterator it = - pending_connections_.begin(); - it != pending_connections_.end(); it++) { - if (!it->second->is_incoming_) { - return true; - } + auto item = discovered_endpoints_.extract(endpoint.endpoint_id); + if (!discovered_endpoints_.count(endpoint.endpoint_id)) { + client->OnEndpointLost(endpoint.service_id, endpoint.endpoint_id); } - return client_proxy->getNumOutgoingConnections() > 0; } -template -bool BasePCPHandler::hasIncomingConnections( - Ptr> client_proxy) { - for (typename PendingConnectionsMap::iterator it = - pending_connections_.begin(); - it != pending_connections_.end(); it++) { - if (it->second->is_incoming_) { - return true; - } - } - return client_proxy->getNumIncomingConnections() > 0; -} - -template -bool BasePCPHandler::canSendOutgoingConnection( - Ptr> client_proxy) { - return true; -} - -template -bool BasePCPHandler::canReceiveIncomingConnection( - Ptr> client_proxy) { - return true; -} - -template -Exception::Value BasePCPHandler::writeConnectionRequestFrame( - Ptr endpoint_channel, const string& local_endpoint_id, - const string& local_endpoint_name, std::int32_t nonce, - const std::vector& supported_mediums) { - Exception::Value write_exception = - endpoint_channel->write(OfflineFrames::forConnectionRequest( - local_endpoint_id, local_endpoint_name, nonce, supported_mediums)); - if (Exception::NONE != write_exception) { - if (Exception::IO == write_exception) { - return write_exception; - } - } - - return Exception::NONE; -} - -template -template -Ptr> BasePCPHandler::runOnPCPHandlerThread( - Ptr> callable) { - return serial_executor_->submit(callable); -} - -template -void BasePCPHandler::onConnectionResponse( - Ptr> client_proxy, const string& endpoint_id, - ConstPtr connection_response_offline_frame) { - ScopedPtr> latch(Platform::createCountDownLatch(1)); - runOnPCPHandlerThread( - MakePtr(new base_pcp_handler::OnConnectionResponseRunnable( - self_, client_proxy, endpoint_id, connection_response_offline_frame, - latch.get()))); - waitForLatch("onConnectionResponse()", latch.get()); -} - -template -bool BasePCPHandler::isPreferred( - Ptr::DiscoveredEndpoint> new_endpoint, - Ptr::DiscoveredEndpoint> old_endpoint) { +bool BasePcpHandler::IsPreferred( + const BasePcpHandler::DiscoveredEndpoint& new_endpoint, + const BasePcpHandler::DiscoveredEndpoint& old_endpoint) { std::vector mediums = - getConnectionMediumsByPriority(); + GetConnectionMediumsByPriority(); // As we iterate through the list of mediums, we see if we run into the new // endpoint's medium or the old endpoint's medium first. - for (std::vector::const_iterator it = - mediums.begin(); - it != mediums.end(); it++) { - const proto::connections::Medium& medium = *it; - if (medium == new_endpoint->getMedium()) { + for (const auto& medium : mediums) { + if (medium == new_endpoint.medium) { // The new endpoint's medium came first. It's preferred! return true; } - if (medium == old_endpoint->getMedium()) { + if (medium == old_endpoint.medium) { // The old endpoint's medium came first. Stick with the old endpoint! return false; } } - // TODO(tracyzhou): Add logging. - assert(false); + std::string medium_string; + for (const auto& medium : mediums) { + absl::StrAppend(&medium_string, medium, "; "); + } + NEARBY_LOG(FATAL, + "Failed to determine preferred medium; bailing out; mediums=%s; " + "new=%d; old=%d", + medium_string.c_str(), new_endpoint.medium, old_endpoint.medium); return false; } -template -bool BasePCPHandler::shouldEnforceTopologyConstraints() { - // Topology constraints only matter for the advertiser. - // For discoverers, we'll always enforce them. - if (getAdvertisingOptions().isNull()) { - return true; - } +Exception BasePcpHandler::OnIncomingConnection( + ClientProxy* client, const ByteArray& remote_endpoint_info, + std::unique_ptr channel, + proto::connections::Medium medium) { + absl::Time start_time = SystemClock::ElapsedRealtime(); - return getAdvertisingOptions()->enforce_topology_constraints; -} - -template -bool BasePCPHandler::autoUpgradeBandwidth() { - if (getAdvertisingOptions().isNull()) { - return true; - } - - return getAdvertisingOptions()->auto_upgrade_bandwidth; -} - -template -Exception::Value BasePCPHandler::onIncomingConnection( - Ptr> client_proxy, const string& remote_device_name, - Ptr endpoint_channel, proto::connections::Medium medium) { - ScopedPtr> scoped_endpoint_channel(endpoint_channel); - - std::int64_t start_time_millis = system_clock_->elapsedRealtime(); - - // Fixes an NPE in ClientProxy.onConnectionResult. The crash happened when + // Fixes an NPE in ClientProxy.OnConnectionAccepted. The crash happened when // the client stopped advertising and we nulled out state, followed by an // incoming connection where we attempted to check that state. - if (!client_proxy->isAdvertising()) { + if (!client->IsAdvertising()) { NEARBY_LOG(WARNING, - "Ignoring incoming connection because client %" PRId64 + "Ignoring incoming connection because client 0x%" PRIX64 " is no longer advertising.", - client_proxy->getClientId()); - return Exception::IO; + client->GetClientId()); + return {Exception::kIo}; } // Endpoints connecting to us will always tell us about themselves first. - ExceptionOr> read_offline_frame = - readConnectionRequestFrame(scoped_endpoint_channel.get()); + ExceptionOr wrapped_frame = + ReadConnectionRequestFrame(channel.get()); - if (!read_offline_frame.ok()) { - if (Exception::IO == read_offline_frame.exception()) { - // TODO(tracyzhou): Add logging. - processPreConnectionInitiationFailure( - client_proxy, medium, "", scoped_endpoint_channel.get(), - /* is_incoming= */ true, start_time_millis, Status::ERROR, - Ptr>()); - return Exception::NONE; + if (!wrapped_frame.ok()) { + if (wrapped_frame.exception()) { + NEARBY_LOG( + ERROR, + "Failed to parse incoming connection request; client_id=0x%" PRIX64 + "; device=%s", + client->GetClientId(), + absl::BytesToHexString(remote_endpoint_info.data()).c_str()); + ProcessPreConnectionInitiationFailure("", channel.get(), {Status::kError}, + nullptr); + return {Exception::kSuccess}; } + return wrapped_frame.GetException(); } - // TODO(tracyzhou): Add logging. - ScopedPtr> scoped_read_offline_frame( - read_offline_frame.result()); - + OfflineFrame& frame = wrapped_frame.result(); const ConnectionRequestFrame& connection_request = - scoped_read_offline_frame->v1().connection_request(); - if (client_proxy->isConnectedToEndpoint(connection_request.endpoint_id())) { - return Exception::IO; + frame.v1().connection_request(); + NEARBY_LOG(INFO, + "Incoming connection request; client_id=0x%" PRIX64 + "; device=%s; id=%s", + client->GetClientId(), + absl::BytesToHexString(remote_endpoint_info.data()).c_str(), + connection_request.endpoint_id().c_str()); + if (client->IsConnectedToEndpoint(connection_request.endpoint_id())) { + return {Exception::kIo}; } // If we've already sent out a connection request to this endpoint, then this // is where we need to decide which connection to break. - if (breakTie(client_proxy, connection_request.endpoint_id(), - connection_request.nonce(), scoped_endpoint_channel.get())) { - return Exception::NONE; + if (BreakTie(client, connection_request.endpoint_id(), + connection_request.nonce(), channel.get())) { + return {Exception::kSuccess}; } // If our child class says we can't accept any more incoming connections, // listen to them. - if (shouldEnforceTopologyConstraints() && - !canReceiveIncomingConnection(client_proxy)) { - return Exception::IO; + if (ShouldEnforceTopologyConstraints() && + !CanReceiveIncomingConnection(client)) { + return {Exception::kIo}; } // The ConnectionRequest frame has two fields that both contain the // EndpointInfo. The legacy field stores it as a string while the newer field // stores it as a byte array. We'll attempt to grab from the newer field, but // will accept the older string if it's all that exists. - const std::string& endpoint_name = connection_request.has_endpoint_info() - ? connection_request.endpoint_info() - : connection_request.endpoint_name(); + const ByteArray endpoint_info{connection_request.has_endpoint_info() + ? connection_request.endpoint_info() + : connection_request.endpoint_name()}; // We've successfully connected to the device, and are now about to jump on to // the EncryptionRunner thread to start running our encryption protocol. We'll - // mark ourselves as pending in case we get another call to requestConnection - // or onIncomingConnection, so that we can cancel the connection if needed. - endpoint_channel = + // mark ourselves as pending in case we get another call to RequestConnection + // or OnIncomingConnection, so that we can cancel the connection if needed. + auto* owned_channel = pending_connections_ - .insert(std::make_pair( - connection_request.endpoint_id(), - PendingConnectionInfo::newIncomingPendingConnectionInfo( - client_proxy, endpoint_name, - scoped_endpoint_channel.release(), connection_request.nonce(), - start_time_millis, advertising_connection_lifecycle_listener_, - OfflineFrames::connectionRequestMediumsToMediums( - connection_request)))) - .first->second->endpoint_channel_.get(); + .emplace(connection_request.endpoint_id(), + PendingConnectionInfo{ + .client = client, + .remote_endpoint_info = endpoint_info, + .nonce = connection_request.nonce(), + .is_incoming = true, + .start_time = start_time, + .listener = advertising_listener_, + .supported_mediums = + parser::ConnectionRequestMediumsToMediums( + connection_request), + .channel = std::move(channel), + }) + .first->second.channel.get(); // Next, we'll set up encryption. - encryption_runner_->startServer( - client_proxy, connection_request.endpoint_id(), endpoint_channel, - MakePtr(new - typename BasePCPHandler::ResultListenerFacade(self_))); - return Exception::NONE; + encryption_runner_.StartServer(client, connection_request.endpoint_id(), + owned_channel, GetResultListener()); + return {Exception::kSuccess}; } -template -bool BasePCPHandler::breakTie(Ptr> client_proxy, - const string& endpoint_id, - std::int32_t incoming_nonce, - Ptr endpoint_channel) { - typename PendingConnectionsMap::iterator it = - pending_connections_.find(endpoint_id); +bool BasePcpHandler::BreakTie(ClientProxy* client, + const std::string& endpoint_id, + std::int32_t incoming_nonce, + EndpointChannel* endpoint_channel) { + auto it = pending_connections_.find(endpoint_id); if (it != pending_connections_.end()) { - Ptr::PendingConnectionInfo> - pending_connection_info = it->second; - - // TODO(tracyzhou): Add logging. + BasePcpHandler::PendingConnectionInfo& info = it->second; + NEARBY_LOG(INFO, "BreakTie: id=%s", endpoint_id.c_str()); // Break the lowest connection. In the (extremely) rare case of a tie, break // both. - if (pending_connection_info->nonce_ > incoming_nonce) { + if (info.nonce > incoming_nonce) { // Our connection won! Clean up their connection. - endpoint_channel->close(); + endpoint_channel->Close(); - // TODO(tracyzhou): Add logging. + NEARBY_LOG(INFO, "BreakTie: We won; id=%s", endpoint_id.c_str()); return true; - } else if (pending_connection_info->nonce_ < incoming_nonce) { + } else if (info.nonce < incoming_nonce) { // Aw, we lost. Clean up our connection, and then we'll let their // connection continue on. - processTieBreakLoss(client_proxy, endpoint_id, pending_connection_info); + ProcessTieBreakLoss(client, endpoint_id, &info); - // TODO(tracyzhou): Add logging. + NEARBY_LOG(INFO, "BreakTie: We lost; id=%s", endpoint_id.c_str()); } else { // Oh. Huh. We both lost. Well, that's awkward. We'll clean up both and // just force the devices to retry. - endpoint_channel->close(); + endpoint_channel->Close(); - processTieBreakLoss(client_proxy, endpoint_id, pending_connection_info); + ProcessTieBreakLoss(client, endpoint_id, &info); - // TODO(tracyzhou): Add logging. + NEARBY_LOG(INFO, "BreakTie: Both lost; id=%s", endpoint_id.c_str()); return true; } } @@ -1206,23 +942,19 @@ bool BasePCPHandler::breakTie(Ptr> client_proxy, return false; } -template -void BasePCPHandler::processTieBreakLoss( - Ptr> client_proxy, const string& endpoint_id, - Ptr connection_info) { - processPreConnectionInitiationFailure( - client_proxy, connection_info->endpoint_channel_->getMedium(), - endpoint_id, connection_info->endpoint_channel_.get(), - connection_info->is_incoming_, connection_info->start_time_millis_, - Status::ENDPOINT_IO_ERROR, connection_info->request_connection_result_); - connection_info->request_connection_result_.clear(); - processPreConnectionResultFailure(client_proxy, endpoint_id); +void BasePcpHandler::ProcessTieBreakLoss( + ClientProxy* client, const std::string& endpoint_id, + BasePcpHandler::PendingConnectionInfo* info) { + ProcessPreConnectionInitiationFailure(endpoint_id, info->channel.get(), + {Status::kEndpointIoError}, + info->result.get()); + info->result = nullptr; + ProcessPreConnectionResultFailure(client, endpoint_id); } -template -void BasePCPHandler::initiateBandwidthUpgrade( - Ptr> client_proxy, const string& endpoint_id, - const std::vector& supported_mediums) { +void BasePcpHandler::InitiateBandwidthUpgrade( + ClientProxy* client, const std::string& endpoint_id, + const std::vector& supported_mediums) { // When we successfully connect to a remote endpoint and a bandwidth upgrade // medium has not yet been decided, we'll pick the highest bandwidth medium // supported by both us and the remote endpoint. Once we pick a medium, all @@ -1232,40 +964,34 @@ void BasePCPHandler::initiateBandwidthUpgrade( // way to prevent mediums, like Wifi Hotspot, from interfering with active // connections (although it's suboptimal for bandwidth throughput). When all // endpoints disconnect, we reset the bandwidth upgrade medium. - if (bandwidth_upgrade_medium_->get() == - proto::connections::Medium::UNKNOWN_MEDIUM) { - bandwidth_upgrade_medium_->set(chooseBestUpgradeMedium(supported_mediums)); + Medium bwu_medium = bwu_medium_.Get(); + if (bwu_medium == Medium::UNKNOWN_MEDIUM) { + bwu_medium = ChooseBestUpgradeMedium(supported_mediums); + bwu_medium_.Set(bwu_medium); } - if (autoUpgradeBandwidth() && (bandwidth_upgrade_medium_->get() != - proto::connections::Medium::UNKNOWN_MEDIUM)) { - bandwidth_upgrade_manager_->initiateBandwidthUpgradeForEndpoint( - client_proxy, endpoint_id, bandwidth_upgrade_medium_->get()); + if (AutoUpgradeBandwidth() && bwu_medium != Medium::UNKNOWN_MEDIUM) { + bwu_manager_->InitiateBwuForEndpoint(client, endpoint_id, bwu_medium); } } -template -proto::connections::Medium BasePCPHandler::chooseBestUpgradeMedium( +proto::connections::Medium BasePcpHandler::ChooseBestUpgradeMedium( const std::vector& their_supported_mediums) { // If the remote side did not report their supported mediums, choose an // appropriate default. std::vector their_mediums = their_supported_mediums; if (their_supported_mediums.empty()) { - their_mediums.push_back(getDefaultUpgradeMedium()); + their_mediums.push_back(GetDefaultUpgradeMedium()); } // Otherwise, pick the best medium we support. std::vector my_mediums = - getConnectionMediumsByPriority(); - for (std::vector::iterator my_medium = - my_mediums.begin(); - my_medium != my_mediums.end(); my_medium++) { - for (std::vector::iterator their_medium = - their_mediums.begin(); - their_medium != their_mediums.end(); their_medium++) { - if (*my_medium == *their_medium) { - return *my_medium; + GetConnectionMediumsByPriority(); + for (const auto& my_medium : my_mediums) { + for (const auto& their_medium : their_mediums) { + if (my_medium == their_medium) { + return my_medium; } } } @@ -1273,304 +999,244 @@ proto::connections::Medium BasePCPHandler::chooseBestUpgradeMedium( return proto::connections::Medium::UNKNOWN_MEDIUM; } -template -void BasePCPHandler::processPreConnectionInitiationFailure( - Ptr> client_proxy, proto::connections::Medium medium, - const string& endpoint_id, Ptr endpoint_channel, - bool is_incoming, std::int64_t start_time_millis, Status::Value status, - Ptr> request_connection_result) { - // Only *remove* this -- as opposed to *destroying* it by invoking - // eraseOwnedPtrFromMap() -- because if endpoint_channel is non-null, it's - // owned by the PendingConnectionInfo in pending_connections_, which means - // destroying the PendingConnectionInfo right now will lead to a dangling - // pointer access when we invoke endpoint_channel->close() below. - ScopedPtr> failed_pending_connection( - base_pcp_handler::removeOwnedPtrFromMap(pending_connections_, - endpoint_id)); - - if (!endpoint_channel.isNull()) { - endpoint_channel->close(); +bool BasePcpHandler::AppendRemoteBluetoothMacAddressEndpoint( + const std::string& endpoint_id, + const std::string& remote_bluetooth_mac_address) { + if (!discovery_options_.allowed.bluetooth) { + return false; } - if (!request_connection_result.isNull()) { - request_connection_result->set(status); + auto it = discovered_endpoints_.equal_range(endpoint_id); + if (it.first == it.second) { + return false; } -} - -template -void BasePCPHandler::processPreConnectionResultFailure( - Ptr> client_proxy, const string& endpoint_id) { - base_pcp_handler::eraseOwnedPtrFromMap(pending_connections_, endpoint_id); - endpoint_manager_->discardEndpoint(client_proxy, endpoint_id); - client_proxy->onConnectionResult(endpoint_id, Status::ERROR); -} - -template -Ptr::DiscoveredEndpoint> -BasePCPHandler::getDiscoveredEndpoint(const string& endpoint_id) { - typename DiscoveredEndpointsMap::iterator it = - discovered_endpoints_.find(endpoint_id); - if (it == discovered_endpoints_.end()) { - return Ptr::DiscoveredEndpoint>(); + auto endpoint = it.first->second.get(); + for (auto item = it.first; item != it.second; item++) { + if (item->second->medium == proto::connections::Medium::BLUETOOTH) { + NEARBY_LOGS(INFO) + << "Cannot append remote Bluetooth MAC Address endpoint, because the " + "endpoint has already been found over Bluetooth " + << "[" << remote_bluetooth_mac_address << "]"; + return false; + } } - return it->second; + + auto remote_bluetooth_device = + GetRemoteBluetoothDevice(remote_bluetooth_mac_address); + if (!remote_bluetooth_device.IsValid()) { + NEARBY_LOGS(INFO) << "Cannot append remote Bluetooth MAC Address endpoint, " + "because a valid " + "Bluetooth device could not be derived " + << "[" << remote_bluetooth_mac_address << "]"; + return false; + } + + auto bluetooth_endpoint = + std::make_shared(BluetoothEndpoint{ + { + endpoint_id, + endpoint->endpoint_info, + endpoint->service_id, + proto::connections::Medium::BLUETOOTH, + WebRtcState::kUnconnectable + }, + remote_bluetooth_device, + }); + + discovered_endpoints_.emplace(endpoint_id, std::move(bluetooth_endpoint)); + return true; } -template -void BasePCPHandler::evaluateConnectionResult( - Ptr> client_proxy, const string& endpoint_id, - bool can_close_immediately) { +bool BasePcpHandler::AppendWebRTCEndpoint(const std::string& endpoint_id) { + if (!discovery_options_.allowed.web_rtc) { + return false; + } + + bool should_connect_web_rtc = false; + auto it = discovered_endpoints_.equal_range(endpoint_id); + if (it.first == it.second) return false; + auto endpoint = it.first->second.get(); + for (auto item = it.first; item != it.second; item++) { + if (item->second->web_rtc_state != WebRtcState::kUnconnectable) { + should_connect_web_rtc = true; + break; + } + } + if (!should_connect_web_rtc) return false; + + auto webrtc_endpoint = + std::make_shared(WebRtcEndpoint{ + { + endpoint_id, + endpoint->endpoint_info, + endpoint->service_id, + proto::connections::Medium::WEB_RTC, + WebRtcState::kConnectable + }, + CreatePeerIdFromAdvertisement( + endpoint->service_id, + endpoint->endpoint_id, + endpoint->endpoint_info), + }); + + discovered_endpoints_.emplace(endpoint_id, std::move(webrtc_endpoint)); + return true; +} + +void BasePcpHandler::EvaluateConnectionResult(ClientProxy* client, + const std::string& endpoint_id, + bool can_close_immediately) { // Short-circuit immediately if we're not in an actionable state yet. We will // be called again once the other side has made their decision. - if (!client_proxy->isConnectionAccepted(endpoint_id) && - !client_proxy->isConnectionRejected(endpoint_id)) { - if (!client_proxy->hasLocalEndpointResponded(endpoint_id)) { - // TODO(tracyzhou): Add logging. - } else if (!client_proxy->hasRemoteEndpointResponded(endpoint_id)) { - // TODO(tracyzhou): Add logging. + if (!client->IsConnectionAccepted(endpoint_id) && + !client->IsConnectionRejected(endpoint_id)) { + if (!client->HasLocalEndpointResponded(endpoint_id)) { + NEARBY_LOG(INFO, "ConnectionResult: local client did not respond; id=%s", + endpoint_id.c_str()); + } else if (!client->HasRemoteEndpointResponded(endpoint_id)) { + NEARBY_LOG(INFO, "ConnectionResult: remote client did not respond; id=%s", + endpoint_id.c_str()); } return; } // Clean up the endpoint channel from our list of 'pending' connections. It's // no longer pending. - typename PendingConnectionsMap::iterator it = - pending_connections_.find(endpoint_id); + auto it = pending_connections_.find(endpoint_id); if (it == pending_connections_.end()) { - // TODO(tracyzhou): Add logging. + NEARBY_LOG(INFO, "No pending connection to evaluate; id=%s", + endpoint_id.c_str()); return; } - ScopedPtr::PendingConnectionInfo>> - connection_info(it->second); - pending_connections_.erase(it); + auto pair = pending_connections_.extract(it); + BasePcpHandler::PendingConnectionInfo& connection_info = pair.mapped(); + bool is_connection_accepted = client->IsConnectionAccepted(endpoint_id); - bool is_connection_accepted = client_proxy->isConnectionAccepted(endpoint_id); - - Status::Value response_code; + Status response_code; if (is_connection_accepted) { - // TODO(tracyzhou): Add logging. - response_code = Status::SUCCESS; + NEARBY_LOG(INFO, "Pending connection accepted; id=%s", endpoint_id.c_str()); + response_code = {Status::kSuccess}; // Both sides have accepted, so we can now start talking over encrypted // channels - std::unique_ptr encryption_context = - connection_info->ukey2_handshake_->ToConnectionContext(); - // Java code throws an HandshakeException. - if (encryption_context == nullptr) { - // TODO(tracyzhou): Add logging. - processPreConnectionResultFailure(client_proxy, endpoint_id); - return; - } + // Now, after both parties accepted connection (presumably after verifying & + // matching security tokens), we are allowed to extract the shared key. + auto ukey2 = std::move(connection_info.ukey2); + bool succeeded = ukey2->VerifyHandshake(); + CHECK(succeeded); // If this fails, it's a UKEY2 protocol bug. + auto context = ukey2->ToConnectionContext(); + CHECK(context); // there is no way how this can fail, if Verify succeeded. + // If it did, it's a UKEY2 protocol bug. - endpoint_channel_manager_->encryptChannelForEndpoint( - endpoint_id, MakeRefCountedPtr(encryption_context.release())); + channel_manager_->EncryptChannelForEndpoint(endpoint_id, + std::move(context)); } else { - // TODO(tracyzhou): Add logging. - response_code = Status::CONNECTION_REJECTED; + NEARBY_LOG(INFO, "Pending connection rejected; id=%s", endpoint_id.c_str()); + response_code = {Status::kConnectionRejected}; } // Invoke the client callback to let it know of the connection result. - client_proxy->onConnectionResult(endpoint_id, response_code); + if (response_code.Ok()) { + client->OnConnectionAccepted(endpoint_id); + } else { + client->OnConnectionRejected(endpoint_id, response_code); + } // If the connection failed, clean everything up and short circuit. if (!is_connection_accepted) { // Clean up the channel in EndpointManager if it's no longer required. if (can_close_immediately) { - endpoint_manager_->discardEndpoint(client_proxy, endpoint_id); + endpoint_manager_->DiscardEndpoint(client, endpoint_id); } else { - pending_rejected_connection_close_alarms_.insert(std::make_pair( + pending_alarms_.emplace( endpoint_id, - MakePtr(new CancelableAlarm( - "BasePCPHandler.evaluateConnectionResult() delayed close", - MakePtr( - new base_pcp_handler:: - EvaluateConnectionResultCancelableAlarmRunnable( - endpoint_manager_, client_proxy, endpoint_id)), - kRejectedConnectionCloseDelayMillis, alarm_executor_.get())))); + CancelableAlarm( + "BasePcpHandler.evaluateConnectionResult() delayed close", + [this, client, endpoint_id]() { + endpoint_manager_->DiscardEndpoint(client, endpoint_id); + }, + kRejectedConnectionCloseDelay, &alarm_executor_)); } return; } // Kick off the bandwidth upgrade for incoming connections. - if (connection_info->is_incoming_) { - initiateBandwidthUpgrade(client_proxy, endpoint_id, - connection_info->supported_mediums_); + if (connection_info.is_incoming) { + InitiateBandwidthUpgrade(client, endpoint_id, + connection_info.supported_mediums); } } -template -ExceptionOr> -BasePCPHandler::readConnectionRequestFrame( - Ptr endpoint_channel) { - if (endpoint_channel.isNull()) { - return ExceptionOr>(Exception::IO); +ExceptionOr BasePcpHandler::ReadConnectionRequestFrame( + EndpointChannel* endpoint_channel) { + if (endpoint_channel == nullptr) { + return ExceptionOr(Exception::kIo); } // To avoid a device connecting but never sending their introductory frame, we // time out the connection after a certain amount of time. CancelableAlarm timeout_alarm( - "PCPHandler(" + this->getStrategy().getName() + - ").readConnectionRequestFrame", - MakePtr( - new base_pcp_handler::ReadConnectionRequestCancelableAlarmRunnable( - endpoint_channel)), - kConnectionRequestReadTimeoutMillis, alarm_executor_.get()); - + absl::StrCat("PcpHandler(", this->GetStrategy().GetName(), + ")::ReadConnectionRequestFrame"), + [endpoint_channel]() { endpoint_channel->Close(); }, + kConnectionRequestReadTimeout, &alarm_executor_); // Do a blocking read to try and find the ConnectionRequestFrame - ExceptionOr> read_bytes = endpoint_channel->read(); - if (!read_bytes.ok()) { - if (Exception::IO == read_bytes.exception()) { - timeout_alarm.cancel(); - return ExceptionOr>(read_bytes.exception()); - } + ExceptionOr wrapped_bytes = endpoint_channel->Read(); + timeout_alarm.Cancel(); + + if (!wrapped_bytes.ok()) { + return ExceptionOr(wrapped_bytes.exception()); } - ScopedPtr> scoped_read_bytes(read_bytes.result()); - ExceptionOr> offline_frame = - OfflineFrames::fromBytes(scoped_read_bytes.get()); - if (!offline_frame.ok()) { - if (Exception::INVALID_PROTOCOL_BUFFER == offline_frame.exception()) { - timeout_alarm.cancel(); - // In Java code, INVALID_PROTOCOL_BUFFER is a subtype of IO exception. - return ExceptionOr>(Exception::IO); - } - } - timeout_alarm.cancel(); - - ScopedPtr> scoped_offline_frame( - offline_frame.result()); - if (V1Frame::CONNECTION_REQUEST != - OfflineFrames::getFrameType(scoped_offline_frame.get())) { - return ExceptionOr>(Exception::IO); + ByteArray bytes = std::move(wrapped_bytes.result()); + ExceptionOr wrapped_frame = parser::FromBytes(bytes); + if (wrapped_frame.GetException().Raised(Exception::kInvalidProtocolBuffer)) { + return ExceptionOr(Exception::kIo); } - return ExceptionOr>(scoped_offline_frame.release()); -} - -template -void BasePCPHandler::waitForLatch(const string& method_name, - Ptr latch) { - Exception::Value await_exception = latch->await(); - if (Exception::NONE != await_exception) { - if (Exception::INTERRUPTED == await_exception) { - // TODO(tracyzhou): Add logging. - // Thread.currentThread().interrupt(); - } - } -} - -template -Status::Value BasePCPHandler::waitForResult( - const string& method_name, std::int64_t client_id, - Ptr> result_future) { - ExceptionOr result = result_future->get(); - if (!result.ok()) { - Exception::Value exception = result.exception(); - if (Exception::INTERRUPTED == exception || - Exception::EXECUTION == exception) { - // TODO(tracyzhou): Add logging. - if (Exception::INTERRUPTED == exception) { - // Thread.currentThread().interrupt(); - } - return Status::ERROR; - } - } - return result.result(); -} - -///////////////////// BasePCPHandler::PendingConnectionInfo /////////////////// - -template -Ptr::PendingConnectionInfo> -BasePCPHandler::PendingConnectionInfo:: - newIncomingPendingConnectionInfo( - Ptr> client_proxy, - const string& remote_endpoint_name, - Ptr endpoint_channel, std::int32_t nonce, - std::int64_t start_time_millis, - Ptr connection_lifecycle_listener, - const std::vector& supported_mediums) { - return MakePtr(new PendingConnectionInfo( - client_proxy, remote_endpoint_name, endpoint_channel, nonce, true, - start_time_millis, connection_lifecycle_listener, - Ptr>(), supported_mediums)); -} - -template -Ptr::PendingConnectionInfo> -BasePCPHandler::PendingConnectionInfo:: - newOutgoingPendingConnectionInfo( - Ptr> client_proxy, - const string& remote_endpoint_name, - Ptr endpoint_channel, std::int32_t nonce, - std::int64_t start_time_millis, - Ptr connection_lifecycle_listener, - Ptr> request_connection_result) { - return MakePtr(new PendingConnectionInfo( - client_proxy, remote_endpoint_name, endpoint_channel, nonce, false, - start_time_millis, connection_lifecycle_listener, - request_connection_result, std::vector())); -} - -template -BasePCPHandler::PendingConnectionInfo::PendingConnectionInfo( - Ptr> client_proxy, const string& remote_endpoint_name, - Ptr endpoint_channel, std::int32_t nonce, bool is_incoming, - std::int64_t start_time_millis, - Ptr connection_lifecycle_listener, - Ptr> request_connection_result, - const std::vector& supported_mediums) - : client_proxy_(client_proxy), - remote_endpoint_name_(remote_endpoint_name), - endpoint_channel_(endpoint_channel), - nonce_(nonce), - is_incoming_(is_incoming), - start_time_millis_(start_time_millis), - connection_lifecycle_listener_(connection_lifecycle_listener), - request_connection_result_(request_connection_result), - supported_mediums_(supported_mediums), - ukey2_handshake_() {} - -template -BasePCPHandler::PendingConnectionInfo::~PendingConnectionInfo() { - if (!request_connection_result_.isNull()) { - request_connection_result_->set(Status::ERROR); + OfflineFrame& frame = wrapped_frame.result(); + if (V1Frame::CONNECTION_REQUEST != parser::GetFrameType(frame)) { + return ExceptionOr(Exception::kIo); } - if (!endpoint_channel_.isNull()) { - endpoint_channel_->close(proto::connections::DisconnectionReason::SHUTDOWN); + return wrapped_frame; +} + +///////////////////// BasePcpHandler::PendingConnectionInfo /////////////////// + +BasePcpHandler::PendingConnectionInfo::~PendingConnectionInfo() { + if (result != nullptr) { + NEARBY_LOG(INFO, "Future was not set; destroying info"); + result->Set({Status::kError}); } - // Done with operational cleanup, now deallocate memory as needed. - ukey2_handshake_.destroy(); -} - -template -void BasePCPHandler::PendingConnectionInfo::setUKey2Handshake( - Ptr ukey2_handshake) { - this->ukey2_handshake_ = ukey2_handshake; -} - -template -void BasePCPHandler::PendingConnectionInfo:: - localEndpointAcceptedConnection(const string& endpoint_id, - Ptr payload_listener) { - if (!ukey2_handshake_->VerifyHandshake()) { - NEARBY_LOG( - FATAL, - "Failed to verify UKEY2 handshake with %s after accepting locally.", - endpoint_id.c_str()); + if (channel != nullptr) { + channel->Close(proto::connections::DisconnectionReason::SHUTDOWN); } - client_proxy_->localEndpointAcceptedConnection(endpoint_id, payload_listener); + // Destroy crypto context now; for some reason, crypto context destructor + // segfaults if it is not destroyed here. + this->ukey2.reset(); } -template -void BasePCPHandler::PendingConnectionInfo:: - localEndpointRejectedConnection(const string& endpoint_id) { - client_proxy_->localEndpointRejectedConnection(endpoint_id); +void BasePcpHandler::PendingConnectionInfo::LocalEndpointAcceptedConnection( + const std::string& endpoint_id, const PayloadListener& payload_listener) { + client->LocalEndpointAcceptedConnection(endpoint_id, payload_listener); +} + +void BasePcpHandler::PendingConnectionInfo::LocalEndpointRejectedConnection( + const std::string& endpoint_id) { + client->LocalEndpointRejectedConnection(endpoint_id); +} + +mediums::PeerId BasePcpHandler::CreatePeerIdFromAdvertisement( + const std::string& service_id, const std::string& endpoint_id, + const ByteArray& endpoint_info) { + std::string seed = + absl::StrCat(service_id, endpoint_id, std::string(endpoint_info)); + return mediums::PeerId::FromSeed(ByteArray(std::move(seed))); } } // namespace connections diff --git a/cpp/core/internal/base_pcp_handler.h b/cpp/core/internal/base_pcp_handler.h index 8415cae0..c7a6ff0b 100644 --- a/cpp/core/internal/base_pcp_handler.h +++ b/cpp/core/internal/base_pcp_handler.h @@ -2,432 +2,443 @@ #define CORE_INTERNAL_BASE_PCP_HANDLER_H_ #include -#include +#include +#include #include -#include "core/internal/bandwidth_upgrade_manager.h" +#include "core/internal/bwu_manager.h" #include "core/internal/client_proxy.h" #include "core/internal/encryption_runner.h" #include "core/internal/endpoint_channel_manager.h" #include "core/internal/endpoint_manager.h" +#include "core/internal/mediums/mediums.h" +#include "core/internal/mediums/webrtc.h" #include "core/internal/pcp.h" #include "core/internal/pcp_handler.h" #include "core/listeners.h" #include "core/options.h" #include "core/status.h" #include "proto/connections/offline_wire_formats.pb.h" -#include "platform/api/atomic_reference.h" -#include "platform/api/count_down_latch.h" -#include "platform/api/settable_future.h" -#include "platform/api/system_clock.h" -#include "platform/cancelable_alarm.h" -#include "platform/port/string.h" -#include "platform/prng.h" -#include "platform/ptr.h" +#include "platform/base/byte_array.h" +#include "platform/base/prng.h" +#include "platform/public/atomic_boolean.h" +#include "platform/public/atomic_reference.h" +#include "platform/public/cancelable_alarm.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/future.h" +#include "platform/public/scheduled_executor.h" +#include "platform/public/single_thread_executor.h" +#include "platform/public/system_clock.h" #include "proto/connections_enums.pb.h" +#include "securegcm/d2d_connection_context_v1.h" #include "securegcm/ukey2_handshake.h" +#include "absl/container/btree_map.h" +#include "absl/container/flat_hash_map.h" +#include "absl/time/time.h" namespace location { namespace nearby { namespace connections { -namespace base_pcp_handler { +// Define a class that supports move operation for pointers using std::swap. +// It replicates std::unique_ptr<> behavior, but it does not own the pointer, +// so it does not attempt destroy it. +// This approach was recommended during code review, as a better alternative to +// reuse of std::unique_ptr<> with custom no-op deleter, for the sake of +// readability. +template +class Swapper { + public: + Swapper(T* pointer) : pointer_(pointer) {} // NOLINT. + Swapper(Swapper&& other) { *this = std::move(other); } + Swapper& operator=(Swapper&& other) { + std::swap(pointer_, other.pointer_); + return *this; + } + T* operator->() const { return pointer_; } + T& operator*() { return *pointer_; } + operator T*() { return pointer_; } // NOLINT. + T* get() const { return pointer_; } + void reset() { pointer_ = nullptr; } -template -class StartAdvertisingCallable; -template -class StopAdvertisingRunnable; -template -class StartDiscoveryCallable; -template -class StopDiscoveryRunnable; -template -class RequestConnectionRunnable; -template -class AcceptConnectionCallable; -template -class RejectConnectionCallable; -template -class ProcessEndpointDisconnectionRunnable; -template -class OnConnectionResponseRunnable; -template -class OnEncryptionSuccessRunnable; -template -class OnEncryptionFailureRunnable; + private: + T* pointer_ = nullptr; +}; -} // namespace base_pcp_handler +template +Swapper MakeSwapper(T* value) { + return Swapper(value); +} -// A base implementation of the PCPHandler interface that takes care of all -// bookkeeping and handshake protocols that are common across all PCPHandler -// implementations -- thus, every concrete PCPHandler implementation must extend +// Represents the WebRtc state that mediums are connectable or not. +enum class WebRtcState { + kUndefined = 0, + kConnectable = 1, + kUnconnectable = 2, +}; + +// A base implementation of the PcpHandler interface that takes care of all +// bookkeeping and handshake protocols that are common across all PcpHandler +// implementations -- thus, every concrete PcpHandler implementation must extend // this class, so that they can focus exclusively on the medium-specific // operations. -template -class BasePCPHandler - : public PCPHandler, - public EndpointManager::IncomingOfflineFrameProcessor { +class BasePcpHandler : public PcpHandler, + public EndpointManager::FrameProcessor { public: - // TODO(tracyzhou): Add SecureRandom. - BasePCPHandler(Ptr > endpoint_manager, - Ptr endpoint_channel_manager, - Ptr bandwidth_upgrade_manager); - ~BasePCPHandler() override; + using FrameProcessor = EndpointManager::FrameProcessor; - // We have been asked by the client to start advertising. Once we successfully - // start advertising, we'll change the ClientProxy's state. - Status::Value startAdvertising( - Ptr > client_proxy, const string& service_id, - const string& local_endpoint_name, - const AdvertisingOptions& advertising_options, - Ptr connection_lifecycle_listener) override; - void stopAdvertising(Ptr > client_proxy) override; + // TODO(apolyudov): Add SecureRandom. + BasePcpHandler(Mediums* mediums, EndpointManager* endpoint_manager, + EndpointChannelManager* channel_manager, + BwuManager* bwu_manager, Pcp pcp); + ~BasePcpHandler() override; + BasePcpHandler(BasePcpHandler&&) = delete; + BasePcpHandler& operator=(BasePcpHandler&&) = delete; - Status::Value startDiscovery( - Ptr > client_proxy, const string& service_id, - const DiscoveryOptions& discovery_options, - Ptr discovery_listener) override; - void stopDiscovery(Ptr > client_proxy) override; + // Starts advertising. Once successfully started, changes ClientProxy's state. + // Notifies ConnectionListener (info.listener) in case of any event. + // See + // https://source.corp.google.com/piper///depot/google3/core/listeners.h;l=78 + Status StartAdvertising(ClientProxy* client, const std::string& service_id, + const ConnectionOptions& options, + const ConnectionRequestInfo& info) override; - Status::Value requestConnection( - Ptr > client_proxy, const string& endpoint_name, - const string& endpoint_id, - Ptr connection_lifecycle_listener) override; - Status::Value acceptConnection( - Ptr > client_proxy, const string& endpoint_id, - Ptr payload_listener) override; - Status::Value rejectConnection(Ptr > client_proxy, - const string& endpoint_id) override; + // Stops Advertising is active, and changes CLientProxy state, + // otherwise does nothing. + void StopAdvertising(ClientProxy* client) override; - proto::connections::Medium getBandwidthUpgradeMedium() override; + // Starts discovery of endpoints that may be advertising. + // Updates ClientProxy state once discovery started. + // DiscoveryListener will get called in case of any event. + Status StartDiscovery(ClientProxy* client, const std::string& service_id, + const ConnectionOptions& options, + const DiscoveryListener& listener) override; + + // Stops Discovery if it is active, and changes CLientProxy state, + // otherwise does nothing. + void StopDiscovery(ClientProxy* client) override; + + void InjectEndpoint(ClientProxy* client, + const std::string& service_id, + const OutOfBandConnectionMetadata& metadata) override; + + // Requests a newly discovered remote endpoint it to form a connection. + // Updates state on ClientProxy. + Status RequestConnection(ClientProxy* client, const std::string& endpoint_id, + const ConnectionRequestInfo& info, + const ConnectionOptions& options) override; + + // Called by either party to accept connection on their part. + // Until both parties call it, connection will not reach a data phase. + // Updates state in ClientProxy. + Status AcceptConnection(ClientProxy* client, const std::string& endpoint_id, + const PayloadListener& payload_listener) override; + + // Called by either party to reject connection on their part. + // If either party does call it, connection will terminate. + // Updates state in ClientProxy. + Status RejectConnection(ClientProxy* client, + const std::string& endpoint_id) override; // @EndpointManagerReaderThread - void processIncomingOfflineFrame( - ConstPtr offline_frame, const string& from_endpoint_id, - Ptr > to_client_proxy, - proto::connections::Medium current_medium) override; + void OnIncomingFrame(OfflineFrame& frame, const std::string& endpoint_id, + ClientProxy* client, + proto::connections::Medium medium) override; // Called when an endpoint disconnects while we're waiting for both sides to // approve/reject the connection. // @EndpointManagerThread - void processEndpointDisconnection( - Ptr > client_proxy, const string& endpoint_id, - Ptr process_disconnection_barrier) override; + void OnEndpointDisconnect(ClientProxy* client, const std::string& endpoint_id, + CountDownLatch* barrier) override; - // Conforms to EncryptionRunner::ResultListener::onEncryptionSuccess(). - // @EncryptionRunnerThread - void onEncryptionSuccessImpl(const string& endpoint_id, - Ptr ukey2_handshake, - const string& authentication_token, - ConstPtr raw_authentication_token); - - // EncryptionRunner::ResultListener::onEncryptionFailure(). - // @EncryptionRunnerThread - void onEncryptionFailureImpl(const string& endpoint_id, - Ptr channel); + Pcp GetPcp() const override { return pcp_; } + Strategy GetStrategy() const override { return strategy_; } + Medium GetBwuMedium() const { return bwu_medium_.Get(); } + void DisconnectFromEndpointManager(); protected: // The result of a call to startAdvertisingImpl() or startDiscoveryImpl(). - class StartOperationResult { - public: - static Ptr error(Status::Value status) { - return MakePtr(new StartOperationResult(status)); - } - - static Ptr success( - const std::vector& mediums) { - // Note: check here and not in the constructor, since for errors we have - // null mediums. - return MakePtr(new StartOperationResult(mediums)); - } - - private: - template - friend class base_pcp_handler::StartAdvertisingCallable; - template - friend class base_pcp_handler::StartDiscoveryCallable; - - explicit StartOperationResult(Status::Value status) - : status_(status), mediums_() {} - explicit StartOperationResult( - const std::vector& mediums) - : status_(Status::SUCCESS), mediums_(mediums) {} - - // The status to be returned to the client. - Status::Value status_; + struct StartOperationResult { + Status status; // If success, the mediums on which we are now advertising/discovering, for // analytics. - std::vector mediums_; + std::vector mediums; }; // Represents an endpoint that we've discovered. Typically, the implementation // will know how to connect to this endpoint if asked. (eg. It holds on to a // BluetoothDevice) - class DiscoveredEndpoint { - public: - virtual ~DiscoveredEndpoint() {} + // + // NOTE(DiscoveredEndpoint): + // Specific protocol is expected to derive from it, as follows: + // struct ProtocolEndpoint : public DiscoveredEndpoint { + // ProtocolContext context; + // }; + // Protocol then allocates instance with std::make_shared(), + // and passes this instance to OnEndpointFound() method. + // When calling OnEndpointLost(), protocol does not need to pass the same + // instance (but it can if implementation desires to do so). + // BasePcpHandler will hold on to the shared_ptr. + struct DiscoveredEndpoint { + DiscoveredEndpoint(std::string endpoint_id, ByteArray endpoint_info, + std::string service_id, + proto::connections::Medium medium, + WebRtcState web_rtc_state) + : endpoint_id(std::move(endpoint_id)), + endpoint_info(std::move(endpoint_info)), + service_id(std::move(service_id)), + medium(medium), + web_rtc_state(web_rtc_state) {} + virtual ~DiscoveredEndpoint() = default; - virtual string getEndpointId() = 0; - virtual string getEndpointName() = 0; - virtual string getServiceId() = 0; - virtual proto::connections::Medium getMedium() = 0; + std::string endpoint_id; + ByteArray endpoint_info; + std::string service_id; + proto::connections::Medium medium; + WebRtcState web_rtc_state; + }; + + struct BluetoothEndpoint : public DiscoveredEndpoint { + BluetoothEndpoint(DiscoveredEndpoint endpoint, BluetoothDevice device) + : DiscoveredEndpoint(std::move(endpoint)), + bluetooth_device(std::move(device)) {} + + BluetoothDevice bluetooth_device; + }; + + struct WifiLanEndpoint : public DiscoveredEndpoint { + WifiLanEndpoint(DiscoveredEndpoint endpoint, WifiLanService service) + : DiscoveredEndpoint(std::move(endpoint)), + wifi_lan_service(std::move(service)) {} + + WifiLanService wifi_lan_service; + }; + + struct WebRtcEndpoint : public DiscoveredEndpoint { + WebRtcEndpoint(DiscoveredEndpoint endpoint, mediums::PeerId peer_id) + : DiscoveredEndpoint(std::move(endpoint)), + peer_id(std::move(peer_id)) {} + + mediums::PeerId peer_id; }; struct ConnectImplResult { - proto::connections::Medium medium; - Status::Value status; - Ptr endpoint_channel; - - explicit ConnectImplResult(Ptr endpoint_channel) - : medium(proto::connections::Medium::UNKNOWN_MEDIUM), - status(Status::SUCCESS), - endpoint_channel(endpoint_channel) {} - ConnectImplResult(proto::connections::Medium medium, Status::Value status) - : medium(medium), status(status), endpoint_channel() {} + proto::connections::Medium medium = + proto::connections::Medium::UNKNOWN_MEDIUM; + Status status = {Status::kError}; + std::unique_ptr endpoint_channel; }; - void runOnPCPHandlerThread(Ptr runnable); + void RunOnPcpHandlerThread(Runnable runnable); - Ptr getAdvertisingOptions(); + BluetoothDevice GetRemoteBluetoothDevice( + const std::string& remote_bluetooth_mac_address); - // @PCPHandlerThread - void onEndpointFound(Ptr > client_proxy, - Ptr endpoint); + ConnectionOptions GetConnectionOptions() const; + ConnectionOptions GetDiscoveryOptions() const; - // @PCPHandlerThread - void onEndpointLost(Ptr > client_proxy, - Ptr endpoint); + // @PcpHandlerThread + void OnEndpointFound(ClientProxy* client, + std::shared_ptr endpoint); - Exception::Value onIncomingConnection( - Ptr > client_proxy, - const string& remote_device_name, Ptr endpoint_channel, + // @PcpHandlerThread + void OnEndpointLost(ClientProxy* client, const DiscoveredEndpoint& endpoint); + + Exception OnIncomingConnection( + ClientProxy* client, const ByteArray& remote_endpoint_info, + std::unique_ptr endpoint_channel, proto::connections::Medium medium); // throws Exception::IO - virtual bool hasOutgoingConnections(Ptr > client_proxy); - virtual bool hasIncomingConnections(Ptr > client_proxy); + virtual bool HasOutgoingConnections(ClientProxy* client) const; + virtual bool HasIncomingConnections(ClientProxy* client) const; - virtual bool canSendOutgoingConnection( - Ptr > client_proxy); - virtual bool canReceiveIncomingConnection( - Ptr > client_proxy); + virtual bool CanSendOutgoingConnection(ClientProxy* client) const; + virtual bool CanReceiveIncomingConnection(ClientProxy* client) const; - // @PCPHandlerThread - virtual Ptr startAdvertisingImpl( - Ptr > client_proxy, const string& service_id, - const string& local_endpoint_id, const string& local_endpoint_name, - const AdvertisingOptions& options) = 0; - // @PCPHandlerThread - virtual Status::Value stopAdvertisingImpl( - Ptr > client_proxy) = 0; + // @PcpHandlerThread + virtual StartOperationResult StartAdvertisingImpl( + ClientProxy* client, const std::string& service_id, + const std::string& local_endpoint_id, + const ByteArray& local_endpoint_info, + const ConnectionOptions& options) = 0; + // @PcpHandlerThread + virtual Status StopAdvertisingImpl(ClientProxy* client) = 0; - // @PCPHandlerThread - virtual Ptr startDiscoveryImpl( - Ptr > client_proxy, const string& service_id, - const DiscoveryOptions& options) = 0; - // @PCPHandlerThread - virtual Status::Value stopDiscoveryImpl( - Ptr > client_proxy) = 0; + // @PcpHandlerThread + virtual StartOperationResult StartDiscoveryImpl( + ClientProxy* client, const std::string& service_id, + const ConnectionOptions& options) = 0; + // @PcpHandlerThread + virtual Status StopDiscoveryImpl(ClientProxy* client) = 0; - // @PCPHandlerThread - virtual ConnectImplResult connectImpl( - Ptr > client_proxy, - Ptr endpoint) = 0; + // @PcpHandlerThread + virtual Status InjectEndpointImpl( + ClientProxy* client, + const std::string& service_id, + const OutOfBandConnectionMetadata& metadata) = 0; + + // @PcpHandlerThread + virtual ConnectImplResult ConnectImpl(ClientProxy* client, + DiscoveredEndpoint* endpoint) = 0; virtual std::vector - getConnectionMediumsByPriority() = 0; - virtual proto::connections::Medium getDefaultUpgradeMedium() = 0; + GetConnectionMediumsByPriority() = 0; + virtual proto::connections::Medium GetDefaultUpgradeMedium() = 0; - Ptr > endpoint_manager_; - Ptr endpoint_channel_manager_; - Ptr bandwidth_upgrade_manager_; + // Returns the first discovered endpoint for the given endpoint_id. + DiscoveredEndpoint* GetDiscoveredEndpoint(const std::string& endpoint_id); + + // Returns a vector of discovered endpoints, sorted in order of decreasing + // preference. + std::vector GetDiscoveredEndpoints( + const std::string& endpoint_id); + + mediums::PeerId CreatePeerIdFromAdvertisement(const string& service_id, + const string& endpoint_id, + const ByteArray& endpoint_info); + + Mediums* mediums_; + EndpointManager* endpoint_manager_; + EndpointChannelManager* channel_manager_; private: - template - friend class base_pcp_handler::StartAdvertisingCallable; - template - friend class base_pcp_handler::StopAdvertisingRunnable; - template - friend class base_pcp_handler::StartDiscoveryCallable; - template - friend class base_pcp_handler::StopDiscoveryRunnable; - template - friend class base_pcp_handler::RequestConnectionRunnable; - template - friend class base_pcp_handler::AcceptConnectionCallable; - template - friend class base_pcp_handler::RejectConnectionCallable; - template - friend class base_pcp_handler::OnConnectionResponseRunnable; - template - friend class base_pcp_handler::ProcessEndpointDisconnectionRunnable; - template - friend class base_pcp_handler::OnEncryptionSuccessRunnable; - template - friend class base_pcp_handler::OnEncryptionFailureRunnable; - - class ResultListenerFacade - : public EncryptionRunner::ResultListener { - public: - explicit ResultListenerFacade(Ptr > impl) - : impl_(impl) {} - - void onEncryptionSuccess( - const string& endpoint_id, - Ptr ukey2_handshake, - const string& authentication_token, - ConstPtr raw_authentication_token) override { - impl_->onEncryptionSuccessImpl(endpoint_id, ukey2_handshake, - authentication_token, - raw_authentication_token); - } - - void onEncryptionFailure(const string& endpoint_id, - Ptr channel) override { - impl_->onEncryptionFailureImpl(endpoint_id, channel); - } - - private: - Ptr > impl_; - }; - - class PendingConnectionInfo { - public: - static Ptr newIncomingPendingConnectionInfo( - Ptr > client_proxy, - const string& remote_endpoint_name, - Ptr endpoint_channel, std::int32_t nonce, - std::int64_t start_time_millis, - Ptr connection_lifecycle_listener, - const std::vector& supported_mediums); - - static Ptr newOutgoingPendingConnectionInfo( - Ptr > client_proxy, - const string& remote_endpoint_name, - Ptr endpoint_channel, std::int32_t nonce, - std::int64_t start_time_millis, - Ptr connection_lifecycle_listener, - Ptr > request_connection_result); - + struct PendingConnectionInfo { + PendingConnectionInfo() = default; + PendingConnectionInfo(PendingConnectionInfo&& other) = default; + PendingConnectionInfo& operator=(PendingConnectionInfo&&) = default; ~PendingConnectionInfo(); - void setUKey2Handshake(Ptr ukey2_handshake); + // Passes crypto context that we acquired in DH session for temporary + // ownership here. + void SetCryptoContext(std::unique_ptr ukey2); - void localEndpointAcceptedConnection(const string& endpoint_id, - Ptr payload_listener); + // Pass Accept notification to client. + void LocalEndpointAcceptedConnection( + const std::string& endpoint_id, + const PayloadListener& payload_listener); - void localEndpointRejectedConnection(const string& endpoint_id); + // Pass Reject notification to client. + void LocalEndpointRejectedConnection(const std::string& endpoint_id); - private: - template - friend class BasePCPHandler; - template - friend class base_pcp_handler::RequestConnectionRunnable; - template - friend class base_pcp_handler::AcceptConnectionCallable; - template - friend class base_pcp_handler::RejectConnectionCallable; - template - friend class base_pcp_handler::OnEncryptionSuccessRunnable; - template - friend class base_pcp_handler::OnEncryptionFailureRunnable; + // Client state tracker to report events to. Never changes. Always valid. + ClientProxy* client = nullptr; + // Peer endpoint info, or empty, if not discovered yet. May change. + ByteArray remote_endpoint_info; + std::int32_t nonce = 0; + bool is_incoming = false; + absl::Time start_time{absl::InfinitePast()}; + // Client callbacks. Always valid. + ConnectionListener listener; + ConnectionOptions options; - PendingConnectionInfo( - Ptr > client_proxy, - const string& remote_endpoint_name, - Ptr endpoint_channel, std::int32_t nonce, - bool is_incoming, std::int64_t start_time_millis, - Ptr connection_lifecycle_listener, - Ptr > request_connection_result, - const std::vector& supported_mediums); + // Only set for outgoing connections. If set, we must call + // result->Set() when connection is established, or rejected. + Swapper> result = nullptr; - Ptr > client_proxy_; - const string remote_endpoint_name_; - // Can be released prior to destructor. - ScopedPtr > endpoint_channel_; - const std::int32_t nonce_; - const bool is_incoming_; - const std::int64_t start_time_millis_; - // Can be released prior to destructor. - ScopedPtr > connection_lifecycle_listener_; + // Only (possibly) vector for incoming connections. + std::vector supported_mediums; - // Only set for outgoing connections. Can be released prior to destructor. - // TODO(b/77783039): Consider creating a one-time-use-only wrapper class - // around the Ptr that's passed in (that also implements the - // SettableFuture interface) so we can avoid the easy-to-forget calls to - // request_connection_result_.clear() peppered through multiple places in - // the code. - Ptr > request_connection_result_; + // Keep track of a channel before we pass it to EndpointChannelManager. + std::unique_ptr channel; - // Only (possibly) set for incoming connections. - const std::vector supported_mediums_; - - // If set, this is owned. - Ptr ukey2_handshake_; + // Crypto context; initially empty; established first thing after channel + // creation by running UKey2 session. While it is in progress, we keep track + // of channel ourselves. Once it is done, we pass channel over to + // EndpointChannelManager. We keep crypto context until connection is + // accepted. Crypto context is passed over to channel_manager_ before + // switching to connected state, where Payload may be exchanged. + std::unique_ptr ukey2; }; - static Exception::Value writeConnectionRequestFrame( - Ptr endpoint_channel, const string& local_endpoint_id, - const string& local_endpoint_name, std::int32_t nonce, + // @EncryptionRunnerThread + // Called internally when DH session has negotiated a key successfully. + void OnEncryptionSuccessImpl(const std::string& endpoint_id, + std::unique_ptr ukey2, + const std::string& auth_token, + const ByteArray& raw_auth_token); + + // @EncryptionRunnerThread + // Called internally when DH session was not able to negotiate a key. + void OnEncryptionFailureImpl(const std::string& endpoint_id, + EndpointChannel* channel); + + EncryptionRunner::ResultListener GetResultListener(); + + void OnEncryptionSuccessRunnable( + const std::string& endpoint_id, + std::unique_ptr ukey2, + const std::string& auth_token, const ByteArray& raw_auth_token); + void OnEncryptionFailureRunnable(const std::string& endpoint_id, + EndpointChannel* endpoint_channel); + + static Exception WriteConnectionRequestFrame( + EndpointChannel* endpoint_channel, const std::string& local_endpoint_id, + const ByteArray& local_endpoint_info, std::int32_t nonce, const std::vector& supported_mediums); - static const std::int64_t kConnectionRequestReadTimeoutMillis; - static const std::int64_t kRejectedConnectionCloseDelayMillis; + static constexpr absl::Duration kConnectionRequestReadTimeout = + absl::Seconds(2); + static constexpr absl::Duration kRejectedConnectionCloseDelay = + absl::Seconds(2); - template - Ptr > runOnPCPHandlerThread(Ptr > callable); - - // The interface deviates from the Java code to convey a better ownership - // story. Ownership of 'connection_response_offline_frame' is transferred to - // the callee by calling this method. - void onConnectionResponse( - Ptr > client_proxy, const string& endpoint_id, - ConstPtr connection_response_offline_frame); + void OnConnectionResponse(ClientProxy* client, const std::string& endpoint_id, + const OfflineFrame& frame); // Returns true if the new endpoint is preferred over the old endpoint. - bool isPreferred(Ptr new_endpoint, - Ptr old_endpoint); + bool IsPreferred(const BasePcpHandler::DiscoveredEndpoint& new_endpoint, + const BasePcpHandler::DiscoveredEndpoint& old_endpoint); - bool shouldEnforceTopologyConstraints(); - bool autoUpgradeBandwidth(); + // Returns true, if connection party should respect the specified topology. + bool ShouldEnforceTopologyConstraints() const; - // Returns true if the incoming connection should be killed. This only happens - // when an incoming connection arrives while we have an outgoing connection to - // the same endpoint and we need to stop one connection. - bool breakTie(Ptr > client_proxy, - const string& endpoint_id, std::int32_t incoming_nonce, - Ptr endpoint_channel); + // Returns true, if connection party should attempt to upgrade itself to + // use a higher bandwidth medium, if it is available. + bool AutoUpgradeBandwidth() const; + + // Returns true if the incoming connection should be killed. This only + // happens when an incoming connection arrives while we have an outgoing + // connection to the same endpoint and we need to stop one connection. + bool BreakTie(ClientProxy* client, const std::string& endpoint_id, + std::int32_t incoming_nonce, EndpointChannel* channel); // We're not sure how far our outgoing connection has gotten. We may (or may - // not) have called ClientProxy.onConnectionInitiated. Therefore, we'll call - // both preInit and preResult failures. - void processTieBreakLoss(Ptr > client_proxy, - const string& endpoint_id, - Ptr connection_info); + // not) have called ClientProxy::OnConnectionInitiated. Therefore, we'll + // call both preInit and preResult failures. + void ProcessTieBreakLoss(ClientProxy* client, const std::string& endpoint_id, + PendingConnectionInfo* info); // Called when an incoming connection has been accepted by both sides. // // @param client_proxy The client // @param endpoint_id The id of the remote device - // @param supported_mediums The mediums supported by the remote device. Empty + // @param supported_mediums The mediums supported by the remote device. + // Empty // for outgoing connections and older devices that don't report their // supported mediums. - void initiateBandwidthUpgrade( - Ptr > client_proxy, const string& endpoint_id, + void InitiateBandwidthUpgrade( + ClientProxy* client, const std::string& endpoint_id, const std::vector& supported_mediums); // Returns the optimal medium supported by both devices. - proto::connections::Medium chooseBestUpgradeMedium( - const std::vector& their_supported_mediums); + proto::connections::Medium ChooseBestUpgradeMedium( + const std::vector& supported_mediums); - // This method should assume ownership of endpoint_id. - void processPreConnectionInitiationFailure( - Ptr > client_proxy, - proto::connections::Medium medium, const string& endpoint_id, - Ptr endpoint_channel, bool is_incoming, - std::int64_t start_time_millis, Status::Value status, - Ptr > request_connection_result); - void processPreConnectionResultFailure( - Ptr > client_proxy, const string& endpoint_id); - Ptr getDiscoveredEndpoint(const string& endpoint_id); + // Returns true if the bluetooth endpoint based on remote bluetooth mac + // address is created and appended into discovered_endpoints_ with key + // endpoint_id. + bool AppendRemoteBluetoothMacAddressEndpoint( + const std::string& endpoint_id, + const std::string& remote_bluetooth_mac_address); + + // Returns true if the webrtc endpoint is created and appended into + // discovered_endpoints_ with key endpoint_id. + bool AppendWebRTCEndpoint(const std::string& endpoint_id); + + void ProcessPreConnectionInitiationFailure(const std::string& endpoint_id, + EndpointChannel* channel, + Status status, + Future* result); + void ProcessPreConnectionResultFailure(ClientProxy* client, + const std::string& endpoint_id); // Called when either side accepts/rejects the connection, but only takes // effect after both have accepted or one side has rejected. @@ -435,73 +446,68 @@ class BasePCPHandler // NOTE: We also take in a 'can_close_immediately' variable. This is because // any writes in transit are dropped when we close. To avoid having a reject // write being dropped (which causes the other side to report - // onResult(DISCONNECTED) instead of onResult(REJECTED)), we delay our close. - // If the other side behaves properly, we shouldn't even see the delay - // (because they will also close the connection). - void evaluateConnectionResult(Ptr > client_proxy, - const string& endpoint_id, + // onResult(DISCONNECTED) instead of onResult(REJECTED)), we delay our + // close. If the other side behaves properly, we shouldn't even see the + // delay (because they will also close the connection). + void EvaluateConnectionResult(ClientProxy* client, + const std::string& endpoint_id, bool can_close_immediately); - ExceptionOr > readConnectionRequestFrame( - Ptr endpoint_channel); + ExceptionOr ReadConnectionRequestFrame( + EndpointChannel* channel); - void waitForLatch(const string& method_name, Ptr latch); - Status::Value waitForResult(const string& method_name, std::int64_t client_id, - Ptr > result_future); + void WaitForLatch(const std::string& method_name, CountDownLatch* latch); + Status WaitForResult(const std::string& method_name, std::int64_t client_id, + Future* future); - ScopedPtr > > - bandwidth_upgrade_medium_; - ScopedPtr > alarm_executor_; - ScopedPtr > serial_executor_; - ScopedPtr > system_clock_; - Prng prng_; + AtomicReference bwu_medium_{Medium::UNKNOWN_MEDIUM}; + ScheduledExecutor alarm_executor_; + SingleThreadExecutor serial_executor_; // A map of endpoint id -> PendingConnectionInfo. Entries in this map imply // that there is an active connection to the endpoint and we're waiting for - // both sides to accept before allowing payloads through. Once the fate of the - // connection is decided (either accepted or rejected), it should be removed - // from this map. - typedef std::map > PendingConnectionsMap; - PendingConnectionsMap pending_connections_; + // both sides to accept before allowing payloads through. Once the fate of + // the connection is decided (either accepted or rejected), it should be + // removed from this map. + absl::flat_hash_map pending_connections_; // A map of endpoint id -> DiscoveredEndpoint. - typedef std::map > DiscoveredEndpointsMap; - DiscoveredEndpointsMap discovered_endpoints_; + absl::btree_multimap> + discovered_endpoints_; // A map of endpoint id -> alarm. These alarms delay closing the // EndpointChannel to give the other side enough time to read the rejection - // message. It's expected that the other side will close the connection after - // reading the message (in which case, this alarm should be cancelled as it's - // no longer needed), but this alarm is the fallback in case that doesn't - // happen. - typedef std::map > - PendingRejectedConnectionCloseAlarmsMap; - PendingRejectedConnectionCloseAlarmsMap - pending_rejected_connection_close_alarms_; + // message. It's expected that the other side will close the connection + // after reading the message (in which case, this alarm should be cancelled + // as it's no longer needed), but this alarm is the fallback in case that + // doesn't happen. + absl::flat_hash_map pending_alarms_; - // The active ClientProxy's advertising constraints. Null if the client hasn't - // started advertising. Note: this is not cleared when the client stops - // advertising because it might still be useful downstream of advertising (eg: - // establishing connections, performing bandwidth upgrades, etc.) - Ptr advertising_options_; + // The active ClientProxy's advertising constraints. Empty() + // returns true if the client hasn't started advertising false otherwise. + // Note: this is not cleared when the client stops advertising because it + // might still be useful downstream of advertising (eg: establishing + // connections, performing bandwidth upgrades, etc.) + ConnectionOptions advertising_options_; // The active ClientProxy's connection lifecycle listener. Non-null while // advertising. - Ptr advertising_connection_lifecycle_listener_; + ConnectionListener advertising_listener_; // The active ClientProxy's discovery constraints. Null if the client // hasn't started discovering. Note: this is not cleared when the client // stops discovering because it might still be useful downstream of // discovery (eg: connection speed, etc.) - Ptr discovery_options_; + ConnectionOptions discovery_options_; - // This should have been a ScopedPtr, but we are making this a Ptr to manually - // control the order of destruction. - Ptr > encryption_runner_; - std::shared_ptr self_{this, [](void*){}}; + AtomicBoolean stop_{false}; + Pcp pcp_; + Strategy strategy_{PcpToStrategy(pcp_)}; + Prng prng_; + EncryptionRunner encryption_runner_; + BwuManager* bwu_manager_; + EndpointManager::FrameProcessor::Handle handle_ = nullptr; }; } // namespace connections } // namespace nearby } // namespace location -#include "core/internal/base_pcp_handler.cc" - #endif // CORE_INTERNAL_BASE_PCP_HANDLER_H_ diff --git a/cpp/core_v2/internal/base_pcp_handler_test.cc b/cpp/core/internal/base_pcp_handler_test.cc similarity index 90% rename from cpp/core_v2/internal/base_pcp_handler_test.cc rename to cpp/core/internal/base_pcp_handler_test.cc index 49175362..29246f9f 100644 --- a/cpp/core_v2/internal/base_pcp_handler_test.cc +++ b/cpp/core/internal/base_pcp_handler_test.cc @@ -1,20 +1,21 @@ -#include "core_v2/internal/base_pcp_handler.h" +#include "core/internal/base_pcp_handler.h" +#include #include #include -#include "core_v2/internal/base_endpoint_channel.h" -#include "core_v2/internal/bwu_manager.h" -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/encryption_runner.h" -#include "core_v2/internal/offline_frames.h" -#include "core_v2/listeners.h" -#include "core_v2/options.h" -#include "core_v2/params.h" +#include "core/internal/base_endpoint_channel.h" +#include "core/internal/bwu_manager.h" +#include "core/internal/client_proxy.h" +#include "core/internal/encryption_runner.h" +#include "core/internal/offline_frames.h" +#include "core/listeners.h" +#include "core/options.h" +#include "core/params.h" #include "proto/connections/offline_wire_formats.pb.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/pipe.h" +#include "platform/base/byte_array.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/pipe.h" #include "proto/connections_enums.pb.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -33,6 +34,8 @@ using ::testing::MockFunction; using ::testing::Return; using ::testing::StrictMock; +constexpr std::array kFakeMacAddress = {'a', 'b', 'c', 'd', 'e', 'f'}; + constexpr BooleanMediumSelector kTestCases[] = { BooleanMediumSelector{}, BooleanMediumSelector{ @@ -111,6 +114,9 @@ class MockPcpHandler : public BasePcpHandler { const ConnectionOptions& options), (override)); MOCK_METHOD(Status, StopDiscoveryImpl, (ClientProxy * client), (override)); + MOCK_METHOD(Status, InjectEndpointImpl, + (ClientProxy * client, const std::string& service_id, + const OutOfBandConnectionMetadata& metadata), (override)); MOCK_METHOD(ConnectImplResult, ConnectImpl, (ClientProxy * client, DiscoveredEndpoint* endpoint), (override)); MOCK_METHOD(proto::connections::Medium, GetDefaultUpgradeMedium, (), @@ -563,6 +569,7 @@ TEST_P(BasePcpHandlerTest, DestructorIsCalledOnProtocolEndpoint) { NEARBY_LOG(INFO, "Closing connection: id=%s", endpoint_id.c_str()); channel_b->Close(); pcp_handler.DisconnectFromEndpointManager(); + bwu.Shutdown(); } EXPECT_EQ(destroyed_flag.load(), mediums_count); } @@ -616,6 +623,57 @@ TEST_P(BasePcpHandlerTest, MultipleMediumsProduceSingleEndpointLostEvent) { INSTANTIATE_TEST_SUITE_P(ParameterizedBasePcpHandlerTest, BasePcpHandlerTest, ::testing::ValuesIn(kTestCases)); +TEST_F(BasePcpHandlerTest, InjectEndpoint) { + std::string service_id{"service"}; + std::string endpoint_id{"ABCD"}; + ClientProxy client; + Mediums m; + EndpointChannelManager ecm; + EndpointManager em(&ecm); + BwuManager bwu(m, em, ecm, {}, {}); + MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); + BooleanMediumSelector allowed{ .bluetooth = true, }; + ConnectionOptions options{ + .allowed = allowed, + .is_out_of_band_connection = true, + }; + EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call); + EXPECT_CALL(pcp_handler, StartDiscoveryImpl(&client, service_id, _)) + .WillOnce(Return(MockPcpHandler::StartOperationResult{ + .status = {Status::kSuccess}, + .mediums = allowed.GetMediums(true), + })); + EXPECT_EQ(pcp_handler.StartDiscovery(&client, service_id, options, + discovery_listener_), + Status{Status::kSuccess}); + EXPECT_TRUE(client.IsDiscovering()); + + EXPECT_CALL(pcp_handler, InjectEndpointImpl(&client, service_id, _)) + .WillOnce(Invoke([&pcp_handler, &endpoint_id]( + ClientProxy* client, + const std::string& service_id, + const OutOfBandConnectionMetadata& metadata) { + pcp_handler.OnEndpointFound( + client, + std::make_shared(MockDiscoveredEndpoint{ + { + endpoint_id, + /*endpoint_info=*/ByteArray{"ABCD"}, + service_id, + Medium::BLUETOOTH, + WebRtcState::kUndefined, + }, + MockContext{nullptr}, + })); + return Status{Status::kSuccess}; + })); + pcp_handler.InjectEndpoint(&client, service_id, + OutOfBandConnectionMetadata{ + .medium = Medium::BLUETOOTH, + .remote_bluetooth_mac_address = ByteArray(kFakeMacAddress), + }); +} + } // namespace } // namespace connections } // namespace nearby diff --git a/cpp/core/internal/ble_advertisement.cc b/cpp/core/internal/ble_advertisement.cc index e97ba86b..805edd4d 100644 --- a/cpp/core/internal/ble_advertisement.cc +++ b/cpp/core/internal/ble_advertisement.cc @@ -1,275 +1,257 @@ #include "core/internal/ble_advertisement.h" -#include +#include -#include "absl/strings/ascii.h" +#include "core/internal/base_pcp_handler.h" +#include "platform/base/base_input_stream.h" +#include "platform/public/logging.h" #include "absl/strings/escaping.h" namespace location { namespace nearby { namespace connections { -const std::uint32_t BLEAdvertisement::kServiceIdHashLength = 3; - -const std::uint32_t BLEAdvertisement::kVersionAndPcpLength = 1; -// Should be defined as EndpointManager::kEndpointIdLength, but that -// involves making BLEAdvertisement templatized on Platform just for -// that one little thing, so forego it (at least for now). -const std::uint32_t BLEAdvertisement::kEndpointIdLength = 4; -const std::uint32_t BLEAdvertisement::kEndpointNameSizeLength = 1; -const std::uint32_t BLEAdvertisement::kBluetoothMacAddressLength = 6; -const std::uint32_t BLEAdvertisement::kMinAdvertisementLength = - kVersionAndPcpLength + kServiceIdHashLength + kEndpointIdLength + - kEndpointNameSizeLength + kBluetoothMacAddressLength; -const std::uint32_t BLEAdvertisement::kMaxEndpointNameLength = 131; - -const std::uint16_t BLEAdvertisement::kVersionBitmask = 0x0E0; -const std::uint16_t BLEAdvertisement::kPCPBitmask = 0x01F; -const std::uint16_t BLEAdvertisement::kEndpointNameLengthBitmask = 0x0FF; - -Ptr BLEAdvertisement::fromBytes( - ConstPtr ble_advertisement_bytes) { - if (ble_advertisement_bytes.isNull()) { - // TODO(ahlee): Logger.atDebug().log("Cannot deserialize BleAdvertisement: - // null bytes passed in."); - return Ptr(); - } - - if (ble_advertisement_bytes->size() < kMinAdvertisementLength) { - // TODO(ahlee): Logger.atDebug().log("Cannot deserialize BleAdvertisement: - // expecting min %d raw bytes, got %d", kMinAdvertisementLength, - // ble_advertisement_bytes->size()); - return Ptr(); - } - - // Start reading the bytes. - const char* ble_advertisement_bytes_read_ptr = - ble_advertisement_bytes->getData(); - - // The first 3 bits are supposed to be the version. - Version::Value version = static_cast( - (*ble_advertisement_bytes_read_ptr & kVersionBitmask) >> 5); - if (version != Version::V1) { - // TODO(ahlee): logger.atDebug().log("Cannot deserialize BleAdvertisement: - // unsupported Version %d", version); - return Ptr(); - } - - PCP::Value pcp = - static_cast(*ble_advertisement_bytes_read_ptr & kPCPBitmask); - ble_advertisement_bytes_read_ptr++; - if (pcp != PCP::P2P_CLUSTER && pcp != PCP::P2P_STAR && - pcp != PCP::P2P_POINT_TO_POINT) { - // TODO(ahlee): logger.atDebug().log("Cannot deserialize BleAdvertisement: - // unsupported V1 PCP %d", pcp); - return Ptr(); - } - - // Avoid leaks. - ScopedPtr > scoped_service_id_hash(MakeConstPtr( - new ByteArray(ble_advertisement_bytes_read_ptr, kServiceIdHashLength))); - ble_advertisement_bytes_read_ptr += kServiceIdHashLength; - - std::string endpoint_id(ble_advertisement_bytes_read_ptr, kEndpointIdLength); - ble_advertisement_bytes_read_ptr += kEndpointIdLength; - - std::uint32_t expected_endpoint_name_length = static_cast( - *ble_advertisement_bytes_read_ptr & kEndpointNameLengthBitmask); - ble_advertisement_bytes_read_ptr++; - - // Check that the stated endpoint_name_length is the same as what we - // received (based off of the length of ble_advertisement_bytes). - std::uint32_t actual_endpoint_name_length = - computeEndpointNameLength(ble_advertisement_bytes); - if (actual_endpoint_name_length < expected_endpoint_name_length) { - // TODO(ahlee): Logger.atDebug().log("Cannot deserialize BleAdvertisement: - // expected endpointName to be %d bytes, got %d bytes", - // expected_endpoint_name_length, actual_endpoint_name_length); - return Ptr(); - } - - std::string endpoint_name(ble_advertisement_bytes_read_ptr, - expected_endpoint_name_length); - ble_advertisement_bytes_read_ptr += expected_endpoint_name_length; - - // Avoid leaks. - ScopedPtr > scoped_bluetooth_mac_address_bytes( - MakeConstPtr(new ByteArray(ble_advertisement_bytes_read_ptr, - kBluetoothMacAddressLength))); - std::string bluetooth_mac_address; - // If the Bluetooth MAC Address bytes are unset or invalid, leave the string - // empty. Otherwise, convert it to the proper colon delimited format. - if (!isBluetoothMacAddressUnset(scoped_bluetooth_mac_address_bytes.get())) { - bluetooth_mac_address = hexBytesToColonDelimitedString( - scoped_bluetooth_mac_address_bytes.get()); - } - - return MakePtr( - new BLEAdvertisement(version, pcp, scoped_service_id_hash.release(), - endpoint_id, endpoint_name, bluetooth_mac_address)); +BleAdvertisement::BleAdvertisement(Version version, Pcp pcp, + const ByteArray& service_id_hash, + const std::string& endpoint_id, + const ByteArray& endpoint_info, + const std::string& bluetooth_mac_address, + const ByteArray& uwb_address, + WebRtcState web_rtc_state) { + DoInitialize(/*fast_advertisement=*/false, version, pcp, service_id_hash, + endpoint_id, endpoint_info, bluetooth_mac_address, uwb_address, + web_rtc_state); } -ConstPtr BLEAdvertisement::toBytes( - Version::Value version, PCP::Value pcp, ConstPtr service_id_hash, - const std::string& endpoint_id, const std::string& endpoint_name, - const std::string& bluetooth_mac_address) { - if (version != Version::V1) { - // TODO(ahlee): logger.atDebug().log("Cannot serialize BleAdvertisement: - // unsupported Version %d", version); - return ConstPtr(); +BleAdvertisement::BleAdvertisement(Version version, Pcp pcp, + const std::string& endpoint_id, + const ByteArray& endpoint_info, + const ByteArray& uwb_address) { + DoInitialize(/*fast_advertisement=*/true, version, pcp, {}, endpoint_id, + endpoint_info, {}, uwb_address, WebRtcState::kUndefined); +} + +void BleAdvertisement::DoInitialize(bool fast_advertisement, Version version, + Pcp pcp, const ByteArray& service_id_hash, + const std::string& endpoint_id, + const ByteArray& endpoint_info, + const std::string& bluetooth_mac_address, + const ByteArray& uwb_address, + WebRtcState web_rtc_state) { + fast_advertisement_ = fast_advertisement; + if (!fast_advertisement_) { + if (service_id_hash.size() != kServiceIdHashLength) return; + } + int max_endpoint_info_length = + fast_advertisement_ ? kMaxFastEndpointInfoLength : kMaxEndpointInfoLength; + if (version != Version::kV1 || endpoint_id.empty() || + endpoint_id.length() != kEndpointIdLength || + endpoint_info.size() > max_endpoint_info_length) { + return; } - if (pcp != PCP::P2P_CLUSTER && pcp != PCP::P2P_STAR && - pcp != PCP::P2P_POINT_TO_POINT) { - // TODO(ahlee): logger.atDebug().log("Cannot serialize BleAdvertisement: - // unsupported V1 PCP %d", pcp); - return ConstPtr(); + switch (pcp) { + case Pcp::kP2pCluster: // Fall through + case Pcp::kP2pStar: // Fall through + case Pcp::kP2pPointToPoint: + break; + default: + return; } - if (endpoint_name.size() > kMaxEndpointNameLength) { - // TODO(ahlee): logger.atDebug().log("Cannot serialize BleAdvertisement: - // expected an endpointName of at most %d bytes but got %d", - // kMaxEndpoingNameLength, endpoint_name.size()); - return ConstPtr(); + version_ = version; + pcp_ = pcp; + service_id_hash_ = service_id_hash; + endpoint_id_ = endpoint_id; + endpoint_info_ = endpoint_info; + uwb_address_ = uwb_address; + if (!fast_advertisement_) { + if (!BluetoothUtils::FromString(bluetooth_mac_address).Empty()) { + bluetooth_mac_address_ = bluetooth_mac_address; + } + + web_rtc_state_ = web_rtc_state; + } +} + +BleAdvertisement::BleAdvertisement(bool fast_advertisement, + const ByteArray& ble_advertisement_bytes) { + fast_advertisement_ = fast_advertisement; + + if (ble_advertisement_bytes.Empty()) { + NEARBY_LOG(ERROR, + "Cannot deserialize BleAdvertisement: null bytes passed in."); + return; } - std::uint32_t ble_advertisement_length = - computeAdvertisementLength(endpoint_name); - Ptr ble_advertisement_bytes{ - new ByteArray{ble_advertisement_length}}; - char* ble_advertisement_bytes_write_ptr = ble_advertisement_bytes->getData(); + int min_advertisement_length = fast_advertisement_ + ? kMinFastAdvertisementLength + : kMinAdvertisementLength; + + if (ble_advertisement_bytes.size() < min_advertisement_length) { + NEARBY_LOG(ERROR, + "Cannot deserialize BleAdvertisement: expecting min %d raw " + "bytes, got %" PRIu64, + kMinAdvertisementLength, ble_advertisement_bytes.size()); + return; + } + + ByteArray advertisement_bytes{ble_advertisement_bytes}; + BaseInputStream base_input_stream{advertisement_bytes}; + // The first 1 byte is supposed to be the version and pcp. + auto version_and_pcp_byte = static_cast(base_input_stream.ReadUint8()); + // The upper 3 bits are supposed to be the version. + version_ = + static_cast((version_and_pcp_byte & kVersionBitmask) >> 5); + if (version_ != Version::kV1) { + NEARBY_LOG(INFO, + "Cannot deserialize BleAdvertisement: unsupported Version %d", + version_); + return; + } + // The lower 5 bits are supposed to be the Pcp. + pcp_ = static_cast(version_and_pcp_byte & kPcpBitmask); + switch (pcp_) { + case Pcp::kP2pCluster: // Fall through + case Pcp::kP2pStar: // Fall through + case Pcp::kP2pPointToPoint: + break; + default: + NEARBY_LOG(INFO, + "Cannot deserialize BleAdvertisement: uunsupported V1 PCP %d", + pcp_); + } + + // The next 3 bytes are supposed to be the service_id_hash if not fast + // advertisment. + if (!fast_advertisement_) + service_id_hash_ = base_input_stream.ReadBytes(kServiceIdHashLength); + + // The next 4 bytes are supposed to be the endpoint_id. + endpoint_id_ = std::string{base_input_stream.ReadBytes(kEndpointIdLength)}; + + // The next 1 byte is supposed to be the length of the endpoint_info. + std::uint32_t expected_endpoint_info_length = base_input_stream.ReadUint8(); + + // The next x bytes are the endpoint info. (Max length is 131 bytes or 17 + // bytes as fast_advertisement being true). + endpoint_info_ = base_input_stream.ReadBytes(expected_endpoint_info_length); + const int max_endpoint_info_length = + fast_advertisement_ ? kMaxFastEndpointInfoLength : kMaxEndpointInfoLength; + if (endpoint_info_.Empty() || + endpoint_info_.size() != expected_endpoint_info_length || + endpoint_info_.size() > max_endpoint_info_length) { + NEARBY_LOG(INFO, + "Cannot deserialize BleAdvertisement(fast advertisement=%d): " + "expected endpointInfo to be %d bytes, got %" PRIu64, + fast_advertisement_, expected_endpoint_info_length, + endpoint_info_.size()); + + // Clear enpoint_id for validity. + endpoint_id_.clear(); + return; + } + + // The next 6 bytes are the bluetooth mac address if not fast advertisment. + if (!fast_advertisement_) { + auto bluetooth_mac_address_bytes = + base_input_stream.ReadBytes(BluetoothUtils::kBluetoothMacAddressLength); + bluetooth_mac_address_ = + BluetoothUtils::ToString(bluetooth_mac_address_bytes); + } + + // The next 1 byte is supposed to be the length of the uwb_address. If the + // next byte is not available then it should be a fast advertisement and skip + // it for remaining bytes. + if (base_input_stream.IsAvailable(1)) { + std::uint32_t expected_uwb_address_length = base_input_stream.ReadUint8(); + // If the length of uwb_address is not zero, then retrieve it. + if (expected_uwb_address_length != 0) { + uwb_address_ = base_input_stream.ReadBytes(expected_uwb_address_length); + if (uwb_address_.Empty() || + uwb_address_.size() != expected_uwb_address_length) { + NEARBY_LOG(INFO, + "Cannot deserialize BleAdvertisement: " + "expected uwbAddress size to be %d bytes, got %" PRIu64, + expected_uwb_address_length, uwb_address_.size()); + + // Clear enpoint_id for validity. + endpoint_id_.clear(); + return; + } + } + + // The next 1 byte is extra field. + if (!fast_advertisement_) { + if (base_input_stream.IsAvailable(kExtraFieldLength)) { + auto extra_field = static_cast(base_input_stream.ReadUint8()); + web_rtc_state_ = (extra_field & kWebRtcConnectableFlagBitmask) == 1 + ? WebRtcState::kConnectable + : WebRtcState::kUnconnectable; + } + } + } + + base_input_stream.Close(); +} + +BleAdvertisement::operator ByteArray() const { + if (!IsValid()) { + return ByteArray(); + } // The first 3 bits are the Version. char version_and_pcp_byte = - static_cast((version << 5) & kVersionBitmask); - // The next 5 bits are the PCP. - version_and_pcp_byte |= static_cast(pcp & kPCPBitmask); - *ble_advertisement_bytes_write_ptr = version_and_pcp_byte; - ble_advertisement_bytes_write_ptr++; + (static_cast(version_) << 5) & kVersionBitmask; + // The next 5 bits are the Pcp. + version_and_pcp_byte |= static_cast(pcp_) & kPcpBitmask; - // The next 24 bits are the service id hash. - memcpy(ble_advertisement_bytes_write_ptr, service_id_hash->getData(), - kServiceIdHashLength); - ble_advertisement_bytes_write_ptr += kServiceIdHashLength; + std::string out; + if (fast_advertisement_) { + // clang-format off + out = absl::StrCat(std::string(1, version_and_pcp_byte), + endpoint_id_, + std::string(1, endpoint_info_.size()), + std::string(endpoint_info_)); + // clang-format on + } else { + // clang-format off + out = absl::StrCat(std::string(1, version_and_pcp_byte), + std::string(service_id_hash_), + endpoint_id_, + std::string(1, endpoint_info_.size()), + std::string(endpoint_info_)); + // clang-format on - // The next 32 bits are the endpoint id. - memcpy(ble_advertisement_bytes_write_ptr, endpoint_id.data(), - kEndpointIdLength); - ble_advertisement_bytes_write_ptr += kEndpointIdLength; - - // The next 8 bits are the length of the endpoint name. - *ble_advertisement_bytes_write_ptr = - static_cast(endpoint_name.size() & kEndpointNameLengthBitmask); - ble_advertisement_bytes_write_ptr++; - - // The next x bits are the endpoint name. (Max length is 131 bytes). - memcpy(ble_advertisement_bytes_write_ptr, endpoint_name.data(), - endpoint_name.size()); - ble_advertisement_bytes_write_ptr += endpoint_name.size(); - - // The next 48 bits are the bluetooth mac address. If bluetooth_mac_address is - // invalid or empty, we get back a null byte array. - // Avoid leaks. - ScopedPtr > scoped_bluetooth_mac_address_bytes( - bluetoothMacAddressToHexBytes(bluetooth_mac_address)); - if (!scoped_bluetooth_mac_address_bytes.isNull()) { - memcpy(ble_advertisement_bytes_write_ptr, - scoped_bluetooth_mac_address_bytes->getData(), - kBluetoothMacAddressLength); - } - ble_advertisement_bytes_write_ptr += kBluetoothMacAddressLength; - - return ConstifyPtr(ble_advertisement_bytes); -} - -std::string BLEAdvertisement::hexBytesToColonDelimitedString( - ConstPtr hex_bytes) { - // Convert the hex bytes to a string. - std::string colon_delimited_string(absl::BytesToHexString( - std::string(hex_bytes->getData(), hex_bytes->size()))); - absl::AsciiStrToUpper(&colon_delimited_string); - - // Insert the colons. - for (int i = colon_delimited_string.length() - 2; i > 0; i -= 2) { - colon_delimited_string.insert(i, ":"); - } - return colon_delimited_string; -} - -// TODO(ahlee): Rename to bluetoothMacAddressHexStringToBytes -ConstPtr BLEAdvertisement::bluetoothMacAddressToHexBytes( - const std::string& bluetooth_mac_address) { - std::string bt_mac_address(bluetooth_mac_address); - - // Remove the colon delimiters. - bt_mac_address.erase( - std::remove(bt_mac_address.begin(), bt_mac_address.end(), ':'), - bt_mac_address.end()); - - // If the bluetooth mac address is invalid (wrong size), return a null byte - // array. - if (bt_mac_address.length() != kBluetoothMacAddressLength * 2) { - return ConstPtr(); - } - - // Convert to bytes. - std::string bt_mac_address_bytes(absl::HexStringToBytes(bt_mac_address)); - return MakeConstPtr( - new ByteArray(bt_mac_address_bytes.data(), bt_mac_address_bytes.size())); -} - -bool BLEAdvertisement::isBluetoothMacAddressUnset( - ConstPtr bluetooth_mac_address_bytes) { - for (int i = 0; i < bluetooth_mac_address_bytes->size(); i++) { - if (bluetooth_mac_address_bytes->getData()[i] != 0) { - return false; + // The next 6 bytes are the bluetooth mac address. If bluetooth_mac_address + // is invalid or empty, we get back a empty byte array. + auto bluetooth_mac_address_bytes{ + BluetoothUtils::FromString(bluetooth_mac_address_)}; + if (!bluetooth_mac_address_bytes.Empty()) { + absl::StrAppend(&out, std::string(bluetooth_mac_address_bytes)); } } - return true; -} -std::uint32_t BLEAdvertisement::computeEndpointNameLength( - ConstPtr ble_advertisement_bytes) { - return ble_advertisement_bytes->size() - kMinAdvertisementLength; -} + // The next bytes are UWB address field. + if (!uwb_address_.Empty()) { + absl::StrAppend(&out, std::string(1, uwb_address_.size())); + absl::StrAppend(&out, std::string(uwb_address_)); + } else if (!fast_advertisement_) { + // Write UWB address with length 0 to be able to read the next field when + // decode. + absl::StrAppend(&out, std::string(1, uwb_address_.size())); + } -std::uint32_t BLEAdvertisement::computeAdvertisementLength( - const std::string& endpoint_name) { - return kMinAdvertisementLength + endpoint_name.size(); -} + // The next 1 byte is extra field. + if (!fast_advertisement_) { + int web_rtc_connectable_flag = + (web_rtc_state_ == WebRtcState::kConnectable) ? 1 : 0; + char extra_field_byte = static_cast(web_rtc_connectable_flag) & + kWebRtcConnectableFlagBitmask; + absl::StrAppend(&out, std::string(1, extra_field_byte)); + } -BLEAdvertisement::BLEAdvertisement(Version::Value version, PCP::Value pcp, - ConstPtr service_id_hash, - const std::string& endpoint_id, - const std::string& endpoint_name, - const std::string& bluetooth_mac_address) - : version_(version), - pcp_(pcp), - service_id_hash_(service_id_hash), - endpoint_id_(endpoint_id), - endpoint_name_(endpoint_name), - bluetooth_mac_address_(bluetooth_mac_address) {} - -BLEAdvertisement::~BLEAdvertisement() { - // Nothing to do. -} - -BLEAdvertisement::Version::Value BLEAdvertisement::getVersion() const { - return version_; -} - -PCP::Value BLEAdvertisement::getPCP() const { return pcp_; } - -std::string BLEAdvertisement::getEndpointId() const { return endpoint_id_; } - -ConstPtr BLEAdvertisement::getServiceIdHash() const { - return service_id_hash_.get(); -} - -std::string BLEAdvertisement::getEndpointName() const { return endpoint_name_; } - -std::string BLEAdvertisement::getBluetoothMacAddress() const { - return bluetooth_mac_address_; + return ByteArray(std::move(out)); } } // namespace connections diff --git a/cpp/core/internal/ble_advertisement.h b/cpp/core/internal/ble_advertisement.h index 64eb6a20..6f262fec 100644 --- a/cpp/core/internal/ble_advertisement.h +++ b/cpp/core/internal/ble_advertisement.h @@ -1,91 +1,109 @@ #ifndef CORE_INTERNAL_BLE_ADVERTISEMENT_H_ #define CORE_INTERNAL_BLE_ADVERTISEMENT_H_ -#include - +#include "core/internal/base_pcp_handler.h" #include "core/internal/pcp.h" -#include "platform/byte_array.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "platform/base/bluetooth_utils.h" +#include "platform/base/byte_array.h" namespace location { namespace nearby { namespace connections { -// Represents the format of the Connections BLE Advertisement used in +// Represents the format of the Connections Ble Advertisement used in // Advertising + Discovery. // -//

[VERSION][PCP][SERVICE_ID_HASH][ENDPOINT_ID][ENDPOINT_NAME_SIZE] -// [ENDPOINT_NAME][BLUETOOTH_MAC] +//

[VERSION][PCP][SERVICE_ID_HASH][ENDPOINT_ID][ENDPOINT_INFO_SIZE] +// [ENDPOINT_INFO][BLUETOOTH_MAC][UWB_ADDRESS_SIZE][UWB_ADDRESS][EXTRA_FIELD] +// +//

The fast version of this advertisement simply omits SERVICE_ID_HASH and +// the Bluetooth MAC address. // //

See go/connections-ble-advertisement for more information. -class BLEAdvertisement { +class BleAdvertisement { public: - // Versions of the BLEAdvertisement. - struct Version { - enum Value { - V1 = 1, - // Version is only allocated 3 bits in the BLEAdvertisement, so this - // can never go beyond V7. - }; + // Versions of the BleAdvertisement. + enum class Version { + kUndefined = 0, + kV1 = 1, + // Version is only allocated 3 bits in the BleAdvertisement, so this + // can never go beyond V7. }; - static Ptr fromBytes( - ConstPtr ble_advertisement_bytes); + static constexpr int kVersionAndPcpLength = 1; + static constexpr int kVersionBitmask = 0x0E0; + static constexpr int kPcpBitmask = 0x01F; + static constexpr int kServiceIdHashLength = 3; + static constexpr int kEndpointIdLength = 4; + static constexpr int kEndpointInfoSizeLength = 1; + static constexpr int kBluetoothMacAddressLength = + BluetoothUtils::kBluetoothMacAddressLength; + static constexpr int kUwbAddressSizeLength = 1; + static constexpr int kExtraFieldLength = 1; + static constexpr int kEndpointInfoLengthBitmask = 0x0FF; + static constexpr int kWebRtcConnectableFlagBitmask = 0x01; + static constexpr int kMinAdvertisementLength = + kVersionAndPcpLength + kServiceIdHashLength + kEndpointIdLength + + kEndpointInfoSizeLength + kBluetoothMacAddressLength; - static ConstPtr toBytes(Version::Value version, PCP::Value pcp, - ConstPtr service_id_hash, - const std::string& endpoint_id, - const std::string& endpoint_name, - const std::string& bluetooth_mac_address); + // The difference between normal and fast advertisements is that the fast one + // omits the SERVICE_ID_HASH and Bluetooth MAC address. This is done to save + // space. + static constexpr int kMinFastAdvertisementLength = kMinAdvertisementLength - + kServiceIdHashLength - + kBluetoothMacAddressLength; + static constexpr int kMaxEndpointInfoLength = 131; + static constexpr int kMaxFastEndpointInfoLength = 17; - static const std::uint32_t kServiceIdHashLength; - static const std::uint32_t kMinAdvertisementLength; - // TODO(ahlee): Make sure names match for both Java and C++ implementations. - static const std::uint32_t kMaxEndpointNameLength; + BleAdvertisement() = default; + BleAdvertisement(Version version, Pcp pcp, const std::string& endpoint_id, + const ByteArray& endpoint_info, + const ByteArray& uwb_address); + BleAdvertisement(Version version, Pcp pcp, const ByteArray& service_id_hash, + const std::string& endpoint_id, + const ByteArray& endpoint_info, + const std::string& bluetooth_mac_address, + const ByteArray& uwb_address, + WebRtcState web_rtc_state); + BleAdvertisement(bool fast_advertisement, + const ByteArray& ble_advertisement_bytes); + BleAdvertisement(const BleAdvertisement&) = default; + BleAdvertisement& operator=(const BleAdvertisement&) = default; + BleAdvertisement(BleAdvertisement&&) = default; + BleAdvertisement& operator=(BleAdvertisement&&) = default; + ~BleAdvertisement() = default; - ~BLEAdvertisement(); + explicit operator ByteArray() const; - Version::Value getVersion() const; - PCP::Value getPCP() const; - ConstPtr getServiceIdHash() const; - std::string getEndpointId() const; - std::string getEndpointName() const; - std::string getBluetoothMacAddress() const; + bool IsValid() const { return !endpoint_id_.empty(); } + bool IsFastAdvertisement() const { return fast_advertisement_; } + Version GetVersion() const { return version_; } + Pcp GetPcp() const { return pcp_; } + ByteArray GetServiceIdHash() const { return service_id_hash_; } + std::string GetEndpointId() const { return endpoint_id_; } + ByteArray GetEndpointInfo() const { return endpoint_info_; } + std::string GetBluetoothMacAddress() const { return bluetooth_mac_address_; } + ByteArray GetUwbAddress() const { return uwb_address_; } + WebRtcState GetWebRtcState() const { return web_rtc_state_; } private: - static std::string hexBytesToColonDelimitedString( - ConstPtr hex_bytes); - // TODO(ahlee): Rename to bluetoothMacAddressHexStringToBytes - static ConstPtr bluetoothMacAddressToHexBytes( - const std::string& bluetooth_mac_address); - static std::uint32_t computeEndpointNameLength( - ConstPtr ble_advertisement_bytes); - static std::uint32_t computeAdvertisementLength( - const std::string& endpoint_name); - static bool isBluetoothMacAddressUnset( - ConstPtr bluetooth_mac_address_bytes); + void DoInitialize(bool fast_advertisement, Version version, Pcp pcp, + const ByteArray& service_id_hash, + const std::string& endpoint_id, + const ByteArray& endpoint_info, + const std::string& bluetooth_mac_address, + const ByteArray& uwb_address, WebRtcState web_rtc_state); - static const std::uint32_t kVersionAndPcpLength; - static const std::uint32_t kEndpointIdLength; - static const std::uint32_t kEndpointNameSizeLength; - static const std::uint32_t kBluetoothMacAddressLength; - static const std::uint16_t kVersionBitmask; - static const std::uint16_t kPCPBitmask; - static const std::uint16_t kEndpointNameLengthBitmask; - - BLEAdvertisement(Version::Value version, PCP::Value pcp, - ConstPtr service_id_hash, - const std::string& endpoint_id, - const std::string& endpoint_name, - const std::string& bluetooth_mac_address); - - const Version::Value version_; - const PCP::Value pcp_; - ScopedPtr > service_id_hash_; - const std::string endpoint_id_; - const std::string endpoint_name_; - const std::string bluetooth_mac_address_; + bool fast_advertisement_ = false; + Version version_{Version::kUndefined}; + Pcp pcp_{Pcp::kUnknown}; + ByteArray service_id_hash_; + std::string endpoint_id_; + ByteArray endpoint_info_; + std::string bluetooth_mac_address_; + // TODO(b/169550050): Define UWB address field. + ByteArray uwb_address_; + WebRtcState web_rtc_state_{WebRtcState::kUndefined}; }; } // namespace connections diff --git a/cpp/core/internal/ble_advertisement_test.cc b/cpp/core/internal/ble_advertisement_test.cc index 683aa6b3..58a9d9dc 100644 --- a/cpp/core/internal/ble_advertisement_test.cc +++ b/cpp/core/internal/ble_advertisement_test.cc @@ -1,8 +1,6 @@ #include "core/internal/ble_advertisement.h" -#include - -#include "platform/port/string.h" +#include "core/internal/base_pcp_handler.h" #include "gtest/gtest.h" namespace location { @@ -10,341 +8,467 @@ namespace nearby { namespace connections { namespace { -const BLEAdvertisement::Version::Value version = BLEAdvertisement::Version::V1; -const PCP::Value pcp = PCP::P2P_CLUSTER; -const char endpoint_id[] = "AB12"; -const char service_id_hash_bytes[] = {0x0A, 0x0B, 0x0C}; -const char endpoint_name[] = - "How much wood can a woodchuck chuck if a wood chuck would chuck wood?"; -const char bluetooth_mac_address[] = "00:00:E6:88:64:13"; +constexpr BleAdvertisement::Version kVersion = BleAdvertisement::Version::kV1; +constexpr Pcp kPcp = Pcp::kP2pCluster; +constexpr absl::string_view kServiceIdHashBytes{"\x0a\x0b\x0c"}; +constexpr absl::string_view kEndpointId{"AB12"}; +constexpr absl::string_view kEndpointName{ + "How much wood can a woodchuck chuck if a wood chuck would chuck wood?"}; +constexpr absl::string_view kFastAdvertisementEndpointName{"Fast Advertise"}; +constexpr absl::string_view kBluetoothMacAddress{"00:00:E6:88:64:13"}; +constexpr WebRtcState kWebRtcState = WebRtcState::kConnectable; -TEST(BLEAdvertisementTest, SerializationDeserializationWorks) { - ScopedPtr > scoped_service_id_hash(new ByteArray( - service_id_hash_bytes, sizeof(service_id_hash_bytes) / sizeof(char))); +// TODO(b/169550050): Implement UWBAddress. +TEST(BleAdvertisementTest, ConstructionWorks) { + ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; + ByteArray endpoint_info{std::string(kEndpointName)}; + BleAdvertisement ble_advertisement{kVersion, + kPcp, + service_id_hash, + std::string(kEndpointId), + endpoint_info, + std::string(kBluetoothMacAddress), + ByteArray{}, + kWebRtcState}; - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes( - version, pcp, ConstifyPtr(scoped_service_id_hash.get()), endpoint_id, - endpoint_name, bluetooth_mac_address)); - ScopedPtr > scoped_ble_advertisement( - BLEAdvertisement::fromBytes(scoped_ble_advertisement_bytes.get())); - - ASSERT_EQ(pcp, scoped_ble_advertisement->getPCP()); - ASSERT_EQ(version, scoped_ble_advertisement->getVersion()); - ASSERT_EQ(endpoint_id, scoped_ble_advertisement->getEndpointId()); - ASSERT_EQ(sizeof(service_id_hash_bytes) / sizeof(char), - scoped_ble_advertisement->getServiceIdHash()->size()); - ASSERT_EQ(0, memcmp(service_id_hash_bytes, - scoped_ble_advertisement->getServiceIdHash()->getData(), - scoped_ble_advertisement->getServiceIdHash()->size())); - ASSERT_EQ(endpoint_name, scoped_ble_advertisement->getEndpointName()); - ASSERT_EQ(bluetooth_mac_address, - scoped_ble_advertisement->getBluetoothMacAddress()); + EXPECT_TRUE(ble_advertisement.IsValid()); + EXPECT_FALSE(ble_advertisement.IsFastAdvertisement()); + EXPECT_EQ(kVersion, ble_advertisement.GetVersion()); + EXPECT_EQ(kPcp, ble_advertisement.GetPcp()); + EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash()); + EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId()); + EXPECT_EQ(endpoint_info, ble_advertisement.GetEndpointInfo()); + EXPECT_EQ(kBluetoothMacAddress, ble_advertisement.GetBluetoothMacAddress()); + EXPECT_EQ(kWebRtcState, ble_advertisement.GetWebRtcState()); } -TEST(BLEAdvertisementTest, SerializationDeserializationWorksWithGoodPCP) { - PCP::Value good_pcp = PCP::P2P_STAR; +TEST(BleAdvertisementTest, ConstructionWorksForFastAdvertisement) { + ByteArray fast_endpoint_info{std::string(kFastAdvertisementEndpointName)}; + BleAdvertisement ble_advertisement{kVersion, + kPcp, + std::string(kEndpointId), + fast_endpoint_info, + ByteArray{}}; - ScopedPtr > scoped_service_id_hash(new ByteArray( - service_id_hash_bytes, sizeof(service_id_hash_bytes) / sizeof(char))); - - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes( - version, good_pcp, ConstifyPtr(scoped_service_id_hash.get()), - endpoint_id, endpoint_name, bluetooth_mac_address)); - ScopedPtr > scoped_ble_advertisement( - BLEAdvertisement::fromBytes(scoped_ble_advertisement_bytes.get())); - - ASSERT_EQ(good_pcp, scoped_ble_advertisement->getPCP()); - ASSERT_EQ(version, scoped_ble_advertisement->getVersion()); - ASSERT_EQ(endpoint_id, scoped_ble_advertisement->getEndpointId()); - ASSERT_EQ(sizeof(service_id_hash_bytes) / sizeof(char), - scoped_ble_advertisement->getServiceIdHash()->size()); - ASSERT_EQ(0, memcmp(service_id_hash_bytes, - scoped_ble_advertisement->getServiceIdHash()->getData(), - scoped_ble_advertisement->getServiceIdHash()->size())); - ASSERT_EQ(endpoint_name, scoped_ble_advertisement->getEndpointName()); - ASSERT_EQ(bluetooth_mac_address, - scoped_ble_advertisement->getBluetoothMacAddress()); + EXPECT_TRUE(ble_advertisement.IsValid()); + EXPECT_TRUE(ble_advertisement.IsFastAdvertisement()); + EXPECT_EQ(kVersion, ble_advertisement.GetVersion()); + EXPECT_EQ(kPcp, ble_advertisement.GetPcp()); + EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId()); + EXPECT_EQ(fast_endpoint_info, ble_advertisement.GetEndpointInfo()); + EXPECT_EQ(WebRtcState::kUndefined, ble_advertisement.GetWebRtcState()); } -TEST(BLEAdvertisementTest, - SerializationDeserializationWorksWithEmptyEndpointName) { - std::string empty_endpoint_name; +TEST(BleAdvertisementTest, ConstructionWorksWithEmptyEndpointInfo) { + ByteArray empty_endpoint_info; - ScopedPtr > scoped_service_id_hash(new ByteArray( - service_id_hash_bytes, sizeof(service_id_hash_bytes) / sizeof(char))); + ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; + BleAdvertisement ble_advertisement{kVersion, + kPcp, + service_id_hash, + std::string(kEndpointId), + empty_endpoint_info, + std::string(kBluetoothMacAddress), + ByteArray{}, + kWebRtcState}; - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes( - version, pcp, ConstifyPtr(scoped_service_id_hash.get()), endpoint_id, - empty_endpoint_name, bluetooth_mac_address)); - ScopedPtr > scoped_ble_advertisement( - BLEAdvertisement::fromBytes(scoped_ble_advertisement_bytes.get())); - - ASSERT_EQ(pcp, scoped_ble_advertisement->getPCP()); - ASSERT_EQ(version, scoped_ble_advertisement->getVersion()); - ASSERT_EQ(endpoint_id, scoped_ble_advertisement->getEndpointId()); - ASSERT_EQ(sizeof(service_id_hash_bytes) / sizeof(char), - scoped_ble_advertisement->getServiceIdHash()->size()); - ASSERT_EQ(0, memcmp(service_id_hash_bytes, - scoped_ble_advertisement->getServiceIdHash()->getData(), - scoped_ble_advertisement->getServiceIdHash()->size())); - ASSERT_EQ(empty_endpoint_name, scoped_ble_advertisement->getEndpointName()); - ASSERT_EQ(bluetooth_mac_address, - scoped_ble_advertisement->getBluetoothMacAddress()); + EXPECT_TRUE(ble_advertisement.IsValid()); + EXPECT_FALSE(ble_advertisement.IsFastAdvertisement()); + EXPECT_EQ(kVersion, ble_advertisement.GetVersion()); + EXPECT_EQ(kPcp, ble_advertisement.GetPcp()); + EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash()); + EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId()); + EXPECT_EQ(empty_endpoint_info, ble_advertisement.GetEndpointInfo()); + EXPECT_EQ(kBluetoothMacAddress, ble_advertisement.GetBluetoothMacAddress()); + EXPECT_EQ(kWebRtcState, ble_advertisement.GetWebRtcState()); } -TEST(BLEAdvertisementTest, - SerializationDeSerializationFailsWithLongEndpointName) { - std::string long_endpoint_name(BLEAdvertisement::kMaxEndpointNameLength + 1, +TEST(BleAdvertisementTest, + ConstructionWorksWithEmptyEndpointInfoForFastAdvertisement) { + ByteArray empty_endpoint_info; + + BleAdvertisement ble_advertisement{kVersion, + kPcp, + std::string(kEndpointId), + empty_endpoint_info, + ByteArray{}}; + + EXPECT_TRUE(ble_advertisement.IsValid()); + EXPECT_TRUE(ble_advertisement.IsFastAdvertisement()); + EXPECT_EQ(kVersion, ble_advertisement.GetVersion()); + EXPECT_EQ(kPcp, ble_advertisement.GetPcp()); + EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId()); + EXPECT_EQ(empty_endpoint_info, ble_advertisement.GetEndpointInfo()); + EXPECT_EQ(WebRtcState::kUndefined, ble_advertisement.GetWebRtcState()); +} + +TEST(BleAdvertisementTest, ConstructionWorksWithEmojiEndpointInfo) { + ByteArray emoji_endpoint_info{std::string("\u0001F450 \u0001F450")}; + + ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; + BleAdvertisement ble_advertisement{kVersion, + kPcp, + service_id_hash, + std::string(kEndpointId), + emoji_endpoint_info, + std::string(kBluetoothMacAddress), + ByteArray{}, + kWebRtcState}; + + EXPECT_TRUE(ble_advertisement.IsValid()); + EXPECT_FALSE(ble_advertisement.IsFastAdvertisement()); + EXPECT_EQ(kVersion, ble_advertisement.GetVersion()); + EXPECT_EQ(kPcp, ble_advertisement.GetPcp()); + EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash()); + EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId()); + EXPECT_EQ(emoji_endpoint_info, ble_advertisement.GetEndpointInfo()); + EXPECT_EQ(kBluetoothMacAddress, ble_advertisement.GetBluetoothMacAddress()); + EXPECT_EQ(kWebRtcState, ble_advertisement.GetWebRtcState()); +} + +TEST(BleAdvertisementTest, + ConstructionWorksWithEmojiEndpointInfoForFastAdvertisement) { + ByteArray emoji_endpoint_info{std::string("\u0001F450 \u0001F450")}; + + BleAdvertisement ble_advertisement{kVersion, + kPcp, + std::string(kEndpointId), + emoji_endpoint_info, + ByteArray{}}; + + EXPECT_TRUE(ble_advertisement.IsValid()); + EXPECT_TRUE(ble_advertisement.IsFastAdvertisement()); + EXPECT_EQ(kVersion, ble_advertisement.GetVersion()); + EXPECT_EQ(kPcp, ble_advertisement.GetPcp()); + EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId()); + EXPECT_EQ(emoji_endpoint_info, ble_advertisement.GetEndpointInfo()); + EXPECT_EQ(WebRtcState::kUndefined, ble_advertisement.GetWebRtcState()); +} + +TEST(BleAdvertisementTest, ConstructionFailsWithLongEndpointInfo) { + std::string long_endpoint_name(BleAdvertisement::kMaxEndpointInfoLength + 1, 'x'); + ByteArray long_endpoint_info{long_endpoint_name}; - ScopedPtr > scoped_service_id_hash(new ByteArray( - service_id_hash_bytes, sizeof(service_id_hash_bytes) / sizeof(char))); + ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; + BleAdvertisement ble_advertisement{kVersion, + kPcp, + service_id_hash, + std::string(kEndpointId), + long_endpoint_info, + std::string(kBluetoothMacAddress), + ByteArray{}, + kWebRtcState}; - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes( - version, pcp, ConstifyPtr(scoped_service_id_hash.get()), endpoint_id, - long_endpoint_name, bluetooth_mac_address)); - - ASSERT_TRUE(scoped_ble_advertisement_bytes.get().isNull()); + EXPECT_FALSE(ble_advertisement.IsValid()); } -TEST(BLEAdvertisementTest, - SerializationDeserializationWorksWithEmojiEndpointName) { - std::string emoji_endpoint_name("\u0001F450 \u0001F450"); +TEST(BleAdvertisementTest, + ConstructionFailsWithLongEndpointInfoForFastAdvertisement) { + std::string long_endpoint_name( + BleAdvertisement::kMaxFastEndpointInfoLength + 1, 'x'); + ByteArray long_endpoint_info{long_endpoint_name}; - ScopedPtr > scoped_service_id_hash(new ByteArray( - service_id_hash_bytes, sizeof(service_id_hash_bytes) / sizeof(char))); + BleAdvertisement ble_advertisement{kVersion, + kPcp, + std::string(kEndpointId), + long_endpoint_info, + ByteArray{}}; - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes( - version, pcp, ConstifyPtr(scoped_service_id_hash.get()), endpoint_id, - emoji_endpoint_name, bluetooth_mac_address)); - ScopedPtr > scoped_ble_advertisement( - BLEAdvertisement::fromBytes(scoped_ble_advertisement_bytes.get())); - - ASSERT_EQ(pcp, scoped_ble_advertisement->getPCP()); - ASSERT_EQ(version, scoped_ble_advertisement->getVersion()); - ASSERT_EQ(endpoint_id, scoped_ble_advertisement->getEndpointId()); - ASSERT_EQ(sizeof(service_id_hash_bytes) / sizeof(char), - scoped_ble_advertisement->getServiceIdHash()->size()); - ASSERT_EQ(0, memcmp(service_id_hash_bytes, - scoped_ble_advertisement->getServiceIdHash()->getData(), - scoped_ble_advertisement->getServiceIdHash()->size())); - ASSERT_EQ(emoji_endpoint_name, scoped_ble_advertisement->getEndpointName()); - ASSERT_EQ(bluetooth_mac_address, - scoped_ble_advertisement->getBluetoothMacAddress()); + EXPECT_FALSE(ble_advertisement.IsValid()); } -TEST(BLEAdvertisementTest, SerializationFailsWithBadVersion) { - BLEAdvertisement::Version::Value bad_version = - static_cast(666); +TEST(BleAdvertisementTest, ConstructionFailsWithBadVersion) { + auto bad_version = static_cast(666); - ScopedPtr > scoped_service_id_hash(new ByteArray( - service_id_hash_bytes, sizeof(service_id_hash_bytes) / sizeof(char))); + ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; + ByteArray endpoint_info{std::string(kEndpointName)}; + BleAdvertisement ble_advertisement{bad_version, + kPcp, + service_id_hash, + std::string(kEndpointId), + endpoint_info, + std::string(kBluetoothMacAddress), + ByteArray{}, + kWebRtcState}; - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes( - bad_version, pcp, ConstifyPtr(scoped_service_id_hash.get()), - endpoint_id, endpoint_name, bluetooth_mac_address)); - - ASSERT_TRUE(scoped_ble_advertisement_bytes.get().isNull()); + EXPECT_FALSE(ble_advertisement.IsValid()); } -TEST(BLEAdvertisementTest, SerializationFailsWithBadPCP) { - PCP::Value bad_pcp = static_cast(666); +TEST(BleAdvertisementTest, + ConstructionFailsWithBadVersionForFastAdvertisement) { + auto bad_version = static_cast(666); - ScopedPtr > scoped_service_id_hash(new ByteArray( - service_id_hash_bytes, sizeof(service_id_hash_bytes) / sizeof(char))); + ByteArray fast_endpoint_info{std::string(kFastAdvertisementEndpointName)}; + BleAdvertisement ble_advertisement{bad_version, + kPcp, + std::string(kEndpointId), + fast_endpoint_info, + ByteArray{}}; - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes( - version, bad_pcp, ConstifyPtr(scoped_service_id_hash.get()), - endpoint_id, endpoint_name, bluetooth_mac_address)); - - ASSERT_TRUE(scoped_ble_advertisement_bytes.get().isNull()); + EXPECT_FALSE(ble_advertisement.IsValid()); } -TEST(BLEAdvertisementTest, SerializationSucceedsWithEmptyBluetoothMacAddress) { +TEST(BleAdvertisementTest, ConstructionFailsWithBadPCP) { + auto bad_pcp = static_cast(666); + + ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; + ByteArray endpoint_info{std::string(kEndpointName)}; + BleAdvertisement ble_advertisement{kVersion, + bad_pcp, + service_id_hash, + std::string(kEndpointId), + endpoint_info, + std::string(kBluetoothMacAddress), + ByteArray{}, + kWebRtcState}; + + EXPECT_FALSE(ble_advertisement.IsValid()); +} + +TEST(BleAdvertisementTest, ConstructionFailsWithBadPCPForFastAdvertisement) { + auto bad_pcp = static_cast(666); + + ByteArray fast_endpoint_info{std::string(kFastAdvertisementEndpointName)}; + BleAdvertisement ble_advertisement{kVersion, + bad_pcp, + std::string(kEndpointId), + fast_endpoint_info, + ByteArray{}}; + + EXPECT_FALSE(ble_advertisement.IsValid()); +} + +TEST(BleAdvertisementTest, ConstructionSucceedsWithEmptyBluetoothMacAddress) { std::string empty_bluetooth_mac_address = ""; - ScopedPtr > scoped_service_id_hash(new ByteArray( - service_id_hash_bytes, sizeof(service_id_hash_bytes) / sizeof(char))); + ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; + ByteArray endpoint_info{std::string(kEndpointName)}; + BleAdvertisement ble_advertisement{kVersion, + kPcp, + service_id_hash, + std::string(kEndpointId), + endpoint_info, + empty_bluetooth_mac_address, + ByteArray{}, + kWebRtcState}; - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes( - version, pcp, ConstifyPtr(scoped_service_id_hash.get()), endpoint_id, - endpoint_name, empty_bluetooth_mac_address)); - ScopedPtr > scoped_ble_advertisement( - BLEAdvertisement::fromBytes(scoped_ble_advertisement_bytes.get())); - - ASSERT_EQ(pcp, scoped_ble_advertisement->getPCP()); - ASSERT_EQ(version, scoped_ble_advertisement->getVersion()); - ASSERT_EQ(endpoint_id, scoped_ble_advertisement->getEndpointId()); - ASSERT_EQ(sizeof(service_id_hash_bytes) / sizeof(char), - scoped_ble_advertisement->getServiceIdHash()->size()); - ASSERT_EQ(0, memcmp(service_id_hash_bytes, - scoped_ble_advertisement->getServiceIdHash()->getData(), - scoped_ble_advertisement->getServiceIdHash()->size())); - ASSERT_EQ(endpoint_name, scoped_ble_advertisement->getEndpointName()); - ASSERT_EQ(empty_bluetooth_mac_address, - scoped_ble_advertisement->getBluetoothMacAddress()); + EXPECT_TRUE(ble_advertisement.IsValid()); } -TEST(BLEAdvertisementTest, - SerializationSucceedsWithInvalidBluetoothMacAddress) { +TEST(BleAdvertisementTest, ConstructionSucceedsWithInvalidBluetoothMacAddress) { std::string bad_bluetooth_mac_address = "022:00"; - ScopedPtr > scoped_service_id_hash(new ByteArray( - service_id_hash_bytes, sizeof(service_id_hash_bytes) / sizeof(char))); + ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; + ByteArray endpoint_info{std::string(kEndpointName)}; + BleAdvertisement ble_advertisement{kVersion, + kPcp, + service_id_hash, + std::string(kEndpointId), + endpoint_info, + bad_bluetooth_mac_address, + ByteArray{}, + kWebRtcState}; - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes( - version, pcp, ConstifyPtr(scoped_service_id_hash.get()), endpoint_id, - endpoint_name, bad_bluetooth_mac_address)); - ScopedPtr > scoped_ble_advertisement( - BLEAdvertisement::fromBytes(scoped_ble_advertisement_bytes.get())); - - ASSERT_EQ(pcp, scoped_ble_advertisement->getPCP()); - ASSERT_EQ(version, scoped_ble_advertisement->getVersion()); - ASSERT_EQ(endpoint_id, scoped_ble_advertisement->getEndpointId()); - ASSERT_EQ(sizeof(service_id_hash_bytes) / sizeof(char), - scoped_ble_advertisement->getServiceIdHash()->size()); - ASSERT_EQ(0, memcmp(service_id_hash_bytes, - scoped_ble_advertisement->getServiceIdHash()->getData(), - scoped_ble_advertisement->getServiceIdHash()->size())); - ASSERT_EQ(endpoint_name, scoped_ble_advertisement->getEndpointName()); - ASSERT_TRUE(scoped_ble_advertisement->getBluetoothMacAddress().empty()); + EXPECT_TRUE(ble_advertisement.IsValid()); + EXPECT_EQ(kVersion, ble_advertisement.GetVersion()); + EXPECT_EQ(kPcp, ble_advertisement.GetPcp()); + EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash()); + EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId()); + EXPECT_EQ(endpoint_info, ble_advertisement.GetEndpointInfo()); + EXPECT_TRUE(ble_advertisement.GetBluetoothMacAddress().empty()); + EXPECT_EQ(kWebRtcState, ble_advertisement.GetWebRtcState()); } -TEST(BLEAdvertisementTest, DeserializationFailsWithNullBytes) { - ScopedPtr > scoped_ble_advertisement( - BLEAdvertisement::fromBytes(ConstPtr())); +TEST(BleAdvertisementTest, ConstructionFromBytesWorks) { + // Serialize good data into a good Ble Advertisement. + ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; + ByteArray endpoint_info{std::string(kEndpointName)}; + BleAdvertisement org_ble_advertisement{kVersion, + kPcp, + service_id_hash, + std::string(kEndpointId), + endpoint_info, + std::string(kBluetoothMacAddress), + ByteArray{}, + kWebRtcState}; + ByteArray ble_advertisement_bytes(org_ble_advertisement); - ASSERT_TRUE(scoped_ble_advertisement.get().isNull()); + BleAdvertisement ble_advertisement{false, ble_advertisement_bytes}; + + EXPECT_TRUE(ble_advertisement.IsValid()); + EXPECT_FALSE(ble_advertisement.IsFastAdvertisement()); + EXPECT_EQ(kVersion, ble_advertisement.GetVersion()); + EXPECT_EQ(kPcp, ble_advertisement.GetPcp()); + EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash()); + EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId()); + EXPECT_EQ(endpoint_info, ble_advertisement.GetEndpointInfo()); + EXPECT_EQ(kBluetoothMacAddress, ble_advertisement.GetBluetoothMacAddress()); + EXPECT_EQ(kWebRtcState, ble_advertisement.GetWebRtcState()); } -TEST(BLEAdvertisementTest, DeserializationFailsWithShortLength) { - // Serialize good data into a good BLE Advertisement. - ScopedPtr > scoped_service_id_hash(new ByteArray( - service_id_hash_bytes, sizeof(service_id_hash_bytes) / sizeof(char))); +TEST(BleAdvertisementTest, ConstructionFromBytesWorksForFastAdvertisement) { + // Serialize good data into a good Ble Advertisement. + ByteArray fast_endpoint_info{std::string(kFastAdvertisementEndpointName)}; + BleAdvertisement org_ble_advertisement{kVersion, + kPcp, + std::string(kEndpointId), + fast_endpoint_info, + ByteArray{}}; + ByteArray ble_advertisement_bytes(org_ble_advertisement); - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes( - version, pcp, ConstifyPtr(scoped_service_id_hash.get()), endpoint_id, - endpoint_name, bluetooth_mac_address)); + BleAdvertisement ble_advertisement{true, ble_advertisement_bytes}; - // Shorten the valid BLE Advertisement. - ScopedPtr > short_ble_advertisement_bytes(MakeConstPtr( - new ByteArray(scoped_ble_advertisement_bytes.get()->getData(), - BLEAdvertisement::kMinAdvertisementLength - 1))); - - // Fail to deserialize the short BLE Advertisement. - ScopedPtr > scoped_short_ble_advertisement( - BLEAdvertisement::fromBytes(short_ble_advertisement_bytes.get())); - ASSERT_TRUE(scoped_short_ble_advertisement.get().isNull()); - - // Make sure deserialization succeeds with the valid BLE Advertisement. - ScopedPtr > scoped_ble_advertisement( - BLEAdvertisement::fromBytes(scoped_ble_advertisement_bytes.get())); - ASSERT_FALSE(scoped_ble_advertisement.get().isNull()); -} - -TEST(BLEAdvertisementTest, DeserializationFailsWithWrongEndpointNameLength) { - // Serialize good data into a good BLE Advertisement. - ScopedPtr > scoped_service_id_hash(new ByteArray( - service_id_hash_bytes, sizeof(service_id_hash_bytes) / sizeof(char))); - - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes( - version, pcp, ConstifyPtr(scoped_service_id_hash.get()), endpoint_id, - endpoint_name, bluetooth_mac_address)); - - // Corrupt the EndpointNameLength bits. - std::string corrupt_ble_advertisement_bytes( - scoped_ble_advertisement_bytes->getData(), - scoped_ble_advertisement_bytes->size()); - corrupt_ble_advertisement_bytes[8] ^= 0x0FF; - ScopedPtr > scoped_corrupt_ble_advertisement_bytes( - MakeConstPtr(new ByteArray(corrupt_ble_advertisement_bytes.data(), - corrupt_ble_advertisement_bytes.size()))); - - // And deserialize the corrupt BLE Advertisement. - ScopedPtr > scoped_ble_advertisement( - BLEAdvertisement::fromBytes( - scoped_corrupt_ble_advertisement_bytes.get())); - ASSERT_TRUE(scoped_ble_advertisement.isNull()); + EXPECT_TRUE(ble_advertisement.IsValid()); + EXPECT_TRUE(ble_advertisement.IsFastAdvertisement()); + EXPECT_EQ(kVersion, ble_advertisement.GetVersion()); + EXPECT_EQ(kPcp, ble_advertisement.GetPcp()); + EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId()); + EXPECT_EQ(fast_endpoint_info, ble_advertisement.GetEndpointInfo()); + EXPECT_EQ(WebRtcState::kUndefined, ble_advertisement.GetWebRtcState()); } // Bytes at the end should be ignored so that they can be used as reserve bytes // in the future. -TEST(BLEAdvertisementTest, DeserializationPassesWithLongLength) { - ScopedPtr > scoped_service_id_hash(new ByteArray( - service_id_hash_bytes, sizeof(service_id_hash_bytes) / sizeof(char))); +TEST(BleAdvertisementTest, ConstructionFromLongLengthBytesWorks) { + // Serialize good data into a good Ble Advertisement. + ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; + ByteArray endpoint_info{std::string(kEndpointName)}; + BleAdvertisement ble_advertisement{kVersion, + kPcp, + service_id_hash, + std::string(kEndpointId), + endpoint_info, + std::string(kBluetoothMacAddress), + ByteArray{}, + kWebRtcState}; + ByteArray ble_advertisement_bytes(ble_advertisement); - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes( - version, pcp, ConstifyPtr(scoped_service_id_hash.get()), endpoint_id, - endpoint_name, bluetooth_mac_address)); + // Add bytes to the end of the valid Ble advertisement. + ByteArray long_ble_advertisement_bytes( + BleAdvertisement::kMinAdvertisementLength + 1000); + ASSERT_LE(ble_advertisement_bytes.size(), + long_ble_advertisement_bytes.size()); + memcpy(long_ble_advertisement_bytes.data(), ble_advertisement_bytes.data(), + ble_advertisement_bytes.size()); - // Add bytes to the end of the valid BLE advertisement. - auto new_array = - new ByteArray(BLEAdvertisement::kMinAdvertisementLength + 1000); - ASSERT_LE(scoped_ble_advertisement_bytes->size(), new_array->size()); - memcpy(new_array->getData(), - scoped_ble_advertisement_bytes->getData(), - scoped_ble_advertisement_bytes->size()); - ScopedPtr > long_ble_advertisement_bytes(MakeConstPtr( - new_array)); + BleAdvertisement long_ble_advertisement{false, long_ble_advertisement_bytes}; - // Deserialize the long BLE advertisement. - ScopedPtr > scoped_long_ble_advertisement( - BLEAdvertisement::fromBytes(long_ble_advertisement_bytes.get())); - ASSERT_FALSE(scoped_long_ble_advertisement.get().isNull()); - - // Make sure deserialization succeeds with the valid BLE Advertisement. - ScopedPtr > scoped_ble_advertisement( - BLEAdvertisement::fromBytes(scoped_ble_advertisement_bytes.get())); - ASSERT_FALSE(scoped_ble_advertisement.get().isNull()); + EXPECT_TRUE(long_ble_advertisement.IsValid()); + EXPECT_EQ(kVersion, long_ble_advertisement.GetVersion()); + EXPECT_EQ(kPcp, long_ble_advertisement.GetPcp()); + EXPECT_EQ(service_id_hash, long_ble_advertisement.GetServiceIdHash()); + EXPECT_EQ(kEndpointId, long_ble_advertisement.GetEndpointId()); + EXPECT_EQ(endpoint_info, long_ble_advertisement.GetEndpointInfo()); + EXPECT_EQ(kBluetoothMacAddress, + long_ble_advertisement.GetBluetoothMacAddress()); + EXPECT_EQ(kWebRtcState, ble_advertisement.GetWebRtcState()); } -TEST(BLEAdvertisementTest, DeserializationWorksWithLongEndpointName) { - // Serialize good data into a good BLE Advertisement. - ScopedPtr > scoped_service_id_hash(new ByteArray( - service_id_hash_bytes, sizeof(service_id_hash_bytes) / sizeof(char))); +TEST(BleAdvertisementTest, ConstructionFromNullBytesFails) { + BleAdvertisement ble_advertisement{false, ByteArray{}}; - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes( - version, pcp, ConstifyPtr(scoped_service_id_hash.get()), endpoint_id, - endpoint_name, bluetooth_mac_address)); + EXPECT_FALSE(ble_advertisement.IsValid()); +} - // Corrupt the EndpointNameLength bits and increase it past the accepted max - // length. - std::string corrupt_ble_advertisement_bytes( - scoped_ble_advertisement_bytes->getData(), - scoped_ble_advertisement_bytes->size()); - corrupt_ble_advertisement_bytes[8] ^= - BLEAdvertisement::kMaxEndpointNameLength + 10; - ScopedPtr > scoped_corrupt_ble_advertisement_bytes( - MakeConstPtr(new ByteArray(corrupt_ble_advertisement_bytes.data(), - corrupt_ble_advertisement_bytes.size()))); - // Increase the size of the advertisement so that there's enough data for the - // now-longer endpoint name. - auto new_array = - new ByteArray(BLEAdvertisement::kMinAdvertisementLength + 1000); - ASSERT_LE(scoped_ble_advertisement_bytes->size(), new_array->size()); - memcpy(new_array->getData(), - scoped_ble_advertisement_bytes->getData(), - scoped_ble_advertisement_bytes->size()); - ScopedPtr > long_ble_advertisement_bytes(MakeConstPtr( - new_array)); +TEST(BleAdvertisementTest, ConstructionFromNullBytesFailsForFastAdvertisement) { + BleAdvertisement ble_advertisement{true, ByteArray{}}; - // And deserialize the changed BLE Advertisement. - ScopedPtr > scoped_ble_advertisement( - BLEAdvertisement::fromBytes(long_ble_advertisement_bytes.get())); - ASSERT_FALSE(scoped_ble_advertisement.isNull()); + EXPECT_FALSE(ble_advertisement.IsValid()); +} + +TEST(BleAdvertisementTest, ConstructionFromShortLengthBytesFails) { + // Serialize good data into a good Ble Advertisement. + ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; + ByteArray endpoint_info{std::string(kEndpointName)}; + BleAdvertisement ble_advertisement{kVersion, + kPcp, + service_id_hash, + std::string(kEndpointId), + endpoint_info, + std::string(kBluetoothMacAddress), + ByteArray{}, + kWebRtcState}; + ByteArray ble_advertisement_bytes(ble_advertisement); + + // Shorten the valid Ble Advertisement. + ByteArray short_ble_advertisement_bytes{ + ble_advertisement_bytes.data(), + BleAdvertisement::kMinAdvertisementLength - 1}; + + BleAdvertisement short_ble_advertisement{false, + short_ble_advertisement_bytes}; + + EXPECT_FALSE(short_ble_advertisement.IsValid()); +} + +TEST(BleAdvertisementTest, + ConstructionFromShortLengthBytesFailsForFastAdvertisement) { + // Serialize good data into a good Ble Advertisement. + ByteArray fast_endpoint_info{std::string(kFastAdvertisementEndpointName)}; + BleAdvertisement ble_advertisement{kVersion, + kPcp, + std::string(kEndpointId), + fast_endpoint_info, + ByteArray{}}; + ByteArray ble_advertisement_bytes(ble_advertisement); + + // Shorten the valid Ble Advertisement. + ByteArray short_ble_advertisement_bytes{ + ble_advertisement_bytes.data(), + BleAdvertisement::kMinAdvertisementLength - 1}; + + BleAdvertisement short_ble_advertisement{true, short_ble_advertisement_bytes}; + + EXPECT_FALSE(short_ble_advertisement.IsValid()); +} + +TEST(BleAdvertisementTest, + ConstructionFromByesWithWrongEndpointInfoLengthFails) { + // Serialize good data into a good Ble Advertisement. + ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; + ByteArray endpoint_info{std::string(kEndpointName)}; + BleAdvertisement ble_advertisement{kVersion, + kPcp, + service_id_hash, + std::string(kEndpointId), + endpoint_info, + std::string(kBluetoothMacAddress), + ByteArray{}, + kWebRtcState}; + ByteArray ble_advertisement_bytes(ble_advertisement); + + // Corrupt the EndpointNameLength bits. + std::string corrupt_ble_advertisement_string(ble_advertisement_bytes); + corrupt_ble_advertisement_string[8] ^= 0x0FF; + ByteArray corrupt_ble_advertisement_bytes(corrupt_ble_advertisement_string); + + BleAdvertisement corrupt_ble_advertisement{false, + corrupt_ble_advertisement_bytes}; + + EXPECT_FALSE(corrupt_ble_advertisement.IsValid()); +} + +TEST(BleAdvertisementTest, + ConstructionFromByesWithWrongEndpointInfoLengthFailsForFastAdvertisement) { + // Serialize good data into a good Ble Advertisement. + ByteArray fast_endpoint_info{std::string(kFastAdvertisementEndpointName)}; + BleAdvertisement ble_advertisement{kVersion, + kPcp, + std::string(kEndpointId), + fast_endpoint_info, + ByteArray{}}; + ByteArray ble_advertisement_bytes = ByteArray(ble_advertisement); + + // Corrupt the EndpointInfoLength bits. + std::string corrupt_ble_advertisement_string(ble_advertisement_bytes); + corrupt_ble_advertisement_string[5] ^= 0x0FF; + ByteArray corrupt_ble_advertisement_bytes(corrupt_ble_advertisement_string); + + BleAdvertisement corrupt_ble_advertisement{true, + corrupt_ble_advertisement_bytes}; + + EXPECT_FALSE(corrupt_ble_advertisement.IsValid()); } } // namespace diff --git a/cpp/core/internal/ble_compat.h b/cpp/core/internal/ble_compat.h deleted file mode 100644 index 264cb39e..00000000 --- a/cpp/core/internal/ble_compat.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef CORE_INTERNAL_BLE_COMPAT_H_ -#define CORE_INTERNAL_BLE_COMPAT_H_ - -#ifndef BLE_V2_IMPLEMENTED -// Flip to true when BLE_V2 is fully implemented and ready to be tested. -#define BLE_V2_IMPLEMENTED 0 -#endif - -#if BLE_V2_IMPLEMENTED - -#include "core/internal/mediums/ble_peripheral.h" -#include "core/internal/mediums/discovered_peripheral_callback.h" -#define BLE_PERIPHERAL location::nearby::connections::mediums::BLEPeripheral -#define DISCOVERED_PERIPHERAL_CALLBACK \ - location::nearby::connections::mediums::DiscoveredPeripheralCallback - -#else - -#include "platform/api/ble.h" -#define BLE_PERIPHERAL location::nearby::BLEPeripheral -#define DISCOVERED_PERIPHERAL_CALLBACK \ - BLE::DiscoveredPeripheralCallback - -#endif // BLE_V2_IMPLEMENTED - -#endif // CORE_INTERNAL_BLE_COMPAT_H_ diff --git a/cpp/core/internal/ble_endpoint_channel.cc b/cpp/core/internal/ble_endpoint_channel.cc index 35924f94..543327d5 100644 --- a/cpp/core/internal/ble_endpoint_channel.cc +++ b/cpp/core/internal/ble_endpoint_channel.cc @@ -2,40 +2,41 @@ #include +#include "platform/public/ble.h" +#include "platform/public/logging.h" + namespace location { namespace nearby { namespace connections { -Ptr BLEEndpointChannel::createOutgoing( - Ptr > medium_manager, const string& channel_name, - Ptr ble_socket) { - return MakePtr(new BLEEndpointChannel(channel_name, ble_socket)); +namespace { + +OutputStream* GetOutputStreamOrNull(BleSocket& socket) { + if (socket.GetRemotePeripheral().IsValid()) return &socket.GetOutputStream(); + return nullptr; } -Ptr BLEEndpointChannel::createIncoming( - Ptr > medium_manager, const string& channel_name, - Ptr ble_socket) { - return MakePtr(new BLEEndpointChannel(channel_name, ble_socket)); +InputStream* GetInputStreamOrNull(BleSocket& socket) { + if (socket.GetRemotePeripheral().IsValid()) return &socket.GetInputStream(); + return nullptr; } -BLEEndpointChannel::BLEEndpointChannel(const string& channel_name, - Ptr ble_socket) - : BaseEndpointChannel(channel_name, ble_socket->getInputStream(), - ble_socket->getOutputStream()), - ble_socket_(ble_socket) {} +} // namespace -BLEEndpointChannel::~BLEEndpointChannel() {} +BleEndpointChannel::BleEndpointChannel(const std::string& channel_name, + BleSocket socket) + : BaseEndpointChannel(channel_name, GetInputStreamOrNull(socket), + GetOutputStreamOrNull(socket)), + ble_socket_(std::move(socket)) {} -proto::connections::Medium BLEEndpointChannel::getMedium() { +proto::connections::Medium BleEndpointChannel::GetMedium() const { return proto::connections::Medium::BLE; } -void BLEEndpointChannel::closeImpl() { - Exception::Value exception = ble_socket_->close(); - if (exception != Exception::NONE) { - if (exception == Exception::IO) { - // TODO(ahlee): Add logging. - } +void BleEndpointChannel::CloseImpl() { + auto status = ble_socket_.Close(); + if (!status.Ok()) { + NEARBY_LOG(INFO, "Failed to close Ble socket: exception=%d", status.value); } } diff --git a/cpp/core/internal/ble_endpoint_channel.h b/cpp/core/internal/ble_endpoint_channel.h index fe336b9b..5672558a 100644 --- a/cpp/core/internal/ble_endpoint_channel.h +++ b/cpp/core/internal/ble_endpoint_channel.h @@ -2,39 +2,24 @@ #define CORE_INTERNAL_BLE_ENDPOINT_CHANNEL_H_ #include "core/internal/base_endpoint_channel.h" -#include "core/internal/medium_manager.h" -#include "platform/api/ble.h" -#include "platform/api/platform.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "platform/public/ble.h" #include "proto/connections_enums.pb.h" namespace location { namespace nearby { namespace connections { -class BLEEndpointChannel : public BaseEndpointChannel { +class BleEndpointChannel final : public BaseEndpointChannel { public: - using Platform = platform::ImplementationPlatform; + // Creates both outgoing and incoming Ble channels. + BleEndpointChannel(const std::string& channel_name, BleSocket socket); - static Ptr createOutgoing( - Ptr > medium_manager, const string& channel_name, - Ptr ble_socket); - static Ptr createIncoming( - Ptr > medium_manager, const string& channel_name, - Ptr ble_socket); - - ~BLEEndpointChannel() override; - - proto::connections::Medium getMedium() override; - - protected: - void closeImpl() override; + proto::connections::Medium GetMedium() const override; private: - BLEEndpointChannel(const string& channel_name, Ptr ble_socket); + void CloseImpl() override; - ScopedPtr > ble_socket_; + BleSocket ble_socket_; }; } // namespace connections diff --git a/cpp/core/internal/bluetooth_device_name.cc b/cpp/core/internal/bluetooth_device_name.cc index d305167d..850c5031 100644 --- a/cpp/core/internal/bluetooth_device_name.cc +++ b/cpp/core/internal/bluetooth_device_name.cc @@ -1,290 +1,202 @@ #include "core/internal/bluetooth_device_name.h" -#include +#include -#include "platform/base64_utils.h" +#include +#include + +#include "platform/base/base64_utils.h" +#include "platform/base/base_input_stream.h" +#include "platform/public/logging.h" +#include "absl/strings/escaping.h" +#include "absl/strings/str_cat.h" namespace location { namespace nearby { namespace connections { -const std::uint32_t BluetoothDeviceName::kServiceIdHashLength = 3; - -const std::uint32_t BluetoothDeviceName::kMaxBluetoothDeviceNameLength = 147; -// Should be defined as ClientProxy::kEndpointIdLength, but that -// involves making BluetoothDeviceName templatized on Platform just for -// that one little thing, so forego it (at least for now). -const std::uint32_t BluetoothDeviceName::kEndpointIdLength = 4; -const std::uint32_t BluetoothDeviceName::kReservedLength = 7; -const std::uint32_t BluetoothDeviceName::kMaxEndpointNameLength = 131; -const std::uint32_t BluetoothDeviceName::kMinBluetoothDeviceNameLength = - kMaxBluetoothDeviceNameLength - kMaxEndpointNameLength; - -const std::uint16_t BluetoothDeviceName::kVersionBitmask = 0x0E0; -const std::uint16_t BluetoothDeviceName::kPCPBitmask = 0x01F; -const std::uint16_t BluetoothDeviceName::kEndpointNameLengthBitmask = 0x0FF; - -Ptr BluetoothDeviceName::fromString( - const std::string& bluetooth_device_name_string) { - ScopedPtr > scoped_bluetooth_device_name_bytes( - Base64Utils::decode(bluetooth_device_name_string)); - if (scoped_bluetooth_device_name_bytes.isNull()) { - // TODO(reznor): logger.atDebug().log("Cannot deserialize - // BluetoothDeviceName: failed Base64 decoding of %s", - // bluetoothDeviceNameString); - return Ptr(); +BluetoothDeviceName::BluetoothDeviceName(Version version, Pcp pcp, + absl::string_view endpoint_id, + const ByteArray& service_id_hash, + const ByteArray& endpoint_info, + const ByteArray& uwb_address, + WebRtcState web_rtc_state) { + if (version != Version::kV1 || endpoint_id.empty() || + endpoint_id.length() != kEndpointIdLength || + service_id_hash.size() != kServiceIdHashLength) { + return; } - - if (scoped_bluetooth_device_name_bytes->size() > - kMaxBluetoothDeviceNameLength) { - // TODO(reznor): logger.atDebug().log("Cannot deserialize - // BluetoothDeviceName: expecting max %d raw bytes, got %d", - // MAX_BLUETOOTH_DEVICE_NAME_LENGTH, bluetoothDeviceNameBytes.length); - return Ptr(); - } - - if (scoped_bluetooth_device_name_bytes->size() < - kMinBluetoothDeviceNameLength) { - // TODO(reznor): logger.atDebug().log("Cannot deserialize - // BluetoothDeviceName: expecting min %d raw bytes, got %d", - // MIN_BLUETOOTH_DEVICE_NAME_LENGTH, bluetoothDeviceNameBytes.length); - return Ptr(); - } - - // The first 3 bits are supposed to be the version. - Version::Value version = static_cast( - (scoped_bluetooth_device_name_bytes->getData()[0] & kVersionBitmask) >> - 5); - - switch (version) { - case Version::V1: - return createV1BluetoothDeviceName( - ConstifyPtr(scoped_bluetooth_device_name_bytes.get())); - - default: - // TODO(reznor): [ANALYTICIZE] This either represents corruption over the - // air, or older versions of GmsCore intermingling with newer ones. - - // TODO(reznor): logger.atDebug().log("Cannot deserialize - // BluetoothDeviceName: unsupported Version %d", version); - return Ptr(); - } -} - -std::string BluetoothDeviceName::asString(Version::Value version, - PCP::Value pcp, - const std::string& endpoint_id, - ConstPtr service_id_hash, - const std::string& endpoint_name) { - std::string usable_endpoint_name(endpoint_name); - if (endpoint_name.size() > kMaxEndpointNameLength) { - // TODO(reznor): logger.atWarning().log("While serializing Advertisement, - // truncating Endpoint Name %s (%d bytes) down to %d bytes", endpointName, - // endpointNameBytes.length, MAX_ENDPOINT_NAME_LENGTH); - usable_endpoint_name.erase(kMaxEndpointNameLength); - } - ScopedPtr > scoped_endpoint_name_bytes( - new ByteArray(usable_endpoint_name.data(), usable_endpoint_name.size())); - - Ptr bluetooth_device_name_bytes; - switch (version) { - case Version::V1: - bluetooth_device_name_bytes = - createV1Bytes(pcp, endpoint_id, service_id_hash, - ConstifyPtr(scoped_endpoint_name_bytes.get())); - if (bluetooth_device_name_bytes.isNull()) { - return ""; - } - break; - - default: - // TODO(reznor): logger.atDebug().log("Cannot serialize - // BluetoothDeviceName: unsupported Version %d", version); - return ""; - } - ScopedPtr > scoped_bluetooth_device_name_bytes( - bluetooth_device_name_bytes); - - // BluetoothDeviceName needs to be binary safe, so apply a Base64 encoding - // over the raw bytes. - return Base64Utils::encode( - ConstifyPtr(scoped_bluetooth_device_name_bytes.get())); -} - -Ptr BluetoothDeviceName::createV1BluetoothDeviceName( - ConstPtr bluetooth_device_name_bytes) { - const char* bluetooth_device_name_bytes_read_ptr = - bluetooth_device_name_bytes->getData(); - - // The first 5 bits of the V1 payload are supposed to be the PCP. - PCP::Value pcp = static_cast( - *bluetooth_device_name_bytes_read_ptr & kPCPBitmask); - bluetooth_device_name_bytes_read_ptr++; - switch (pcp) { - case PCP::P2P_CLUSTER: // Fall through - case PCP::P2P_STAR: // Fall through - case PCP::P2P_POINT_TO_POINT: { - // The next 32 bits are supposed to be the endpoint_id. - std::string endpoint_id(bluetooth_device_name_bytes_read_ptr, - kEndpointIdLength); - bluetooth_device_name_bytes_read_ptr += kEndpointIdLength; + case Pcp::kP2pCluster: // Fall through + case Pcp::kP2pStar: // Fall through + case Pcp::kP2pPointToPoint: + break; + default: + return; + } - // The next 24 bits are supposed to be the scoped_service_id_hash. - ScopedPtr > scoped_service_id_hash( - MakeConstPtr(new ByteArray(bluetooth_device_name_bytes_read_ptr, - kServiceIdHashLength))); - bluetooth_device_name_bytes_read_ptr += kServiceIdHashLength; + version_ = version; + pcp_ = pcp; + endpoint_id_ = std::string(endpoint_id); + service_id_hash_ = service_id_hash; + endpoint_info_ = endpoint_info; + uwb_address_ = uwb_address; + web_rtc_state_ = web_rtc_state; +} - // The next 56 bits are supposed to be reserved, and can be left - // untouched. - bluetooth_device_name_bytes_read_ptr += kReservedLength; +BluetoothDeviceName::BluetoothDeviceName( + absl::string_view bluetooth_device_name_string) { + ByteArray bluetooth_device_name_bytes = + Base64Utils::Decode(bluetooth_device_name_string); - // The next 8 bits are supposed to be the length of the endpoint_name. - std::uint32_t expected_endpoint_name_length = static_cast( - *bluetooth_device_name_bytes_read_ptr & kEndpointNameLengthBitmask); - bluetooth_device_name_bytes_read_ptr++; + if (bluetooth_device_name_bytes.Empty()) { + NEARBY_LOG( + INFO, + "Cannot deserialize BluetoothDeviceName: failed Base64 decoding of %s", + std::string(bluetooth_device_name_string).c_str()); + return; + } - // Check that the stated endpoint_name_length is the same as what we - // received (based off of the length of bluetooth_device_name_bytes). - std::uint32_t actual_endpoint_name_length = - computeEndpointNameLength(bluetooth_device_name_bytes); - if (actual_endpoint_name_length != expected_endpoint_name_length) { - // TODO(reznor): logger.atDebug().log("Cannot deserialize - // BluetoothDeviceName: expected endpointName to be %d bytes, got %d - // bytes", expectedEndpointNameLength, actualEndpointNameLength); - return Ptr(); + if (bluetooth_device_name_bytes.size() < kMinBluetoothDeviceNameLength) { + NEARBY_LOG(INFO, + "Cannot deserialize BluetoothDeviceName: expecting min %d raw " + "bytes, got %" PRIu64, + kMinBluetoothDeviceNameLength, + bluetooth_device_name_bytes.size()); + return; + } + + BaseInputStream base_input_stream{bluetooth_device_name_bytes}; + // The first 1 byte is supposed to be the version and pcp. + auto version_and_pcp_byte = static_cast(base_input_stream.ReadUint8()); + // The upper 3 bits are supposed to be the version. + version_ = + static_cast((version_and_pcp_byte & kVersionBitmask) >> 5); + if (version_ != Version::kV1) { + NEARBY_LOG(INFO, + "Cannot deserialize BluetoothDeviceName: unsupported version=%d", + version_); + return; + } + // The lower 5 bits are supposed to be the Pcp. + pcp_ = static_cast(version_and_pcp_byte & kPcpBitmask); + switch (pcp_) { + case Pcp::kP2pCluster: // Fall through + case Pcp::kP2pStar: // Fall through + case Pcp::kP2pPointToPoint: + break; + default: + NEARBY_LOG( + INFO, "Cannot deserialize BluetoothDeviceName: unsupported V1 PCP %d", + pcp_); + return; + } + + // The next 4 bytes are supposed to be the endpoint_id. + endpoint_id_ = std::string{base_input_stream.ReadBytes(kEndpointIdLength)}; + + // The next 3 bytes are supposed to be the service_id_hash. + service_id_hash_ = base_input_stream.ReadBytes(kServiceIdHashLength); + + + // The next 1 byte is field containning WebRtc state. + auto field_byte = static_cast(base_input_stream.ReadUint8()); + web_rtc_state_ = (field_byte & kWebRtcConnectableFlagBitmask) == 1 + ? WebRtcState::kConnectable + : WebRtcState::kUnconnectable; + + // The next 6 bytes are supposed to be reserved, and can be left + // untouched. + base_input_stream.ReadBytes(kReservedLength); + + // The next 1 byte is supposed to be the length of the endpoint_info. + std::uint32_t expected_endpoint_info_length = base_input_stream.ReadUint8(); + + // The rest bytes are supposed to be the endpoint_info + endpoint_info_ = base_input_stream.ReadBytes(expected_endpoint_info_length); + if (endpoint_info_.Empty() || + endpoint_info_.size() != expected_endpoint_info_length) { + NEARBY_LOG(INFO, + "Cannot deserialize BluetoothDeviceName: expected " + "endpoint info to be %d bytes, got %" PRIu64, + expected_endpoint_info_length, endpoint_info_.size()); + + // Clear enpoint_id for validadity. + endpoint_id_.clear(); + return; + } + + // If the input stream has extra bytes, it's for UWB address. The first byte + // is the address length. It can be 2-byte short address or 8-byte extended + // address. + if (base_input_stream.IsAvailable(1)) { + // The next 1 byte is supposed to be the length of the uwb_address. + std::uint32_t expected_uwb_address_length = base_input_stream.ReadUint8(); + // If the length of usb_address is not zero, then retrieve it. + if (expected_uwb_address_length != 0) { + uwb_address_ = base_input_stream.ReadBytes(expected_uwb_address_length); + if (uwb_address_.Empty() || + uwb_address_.size() != expected_uwb_address_length) { + NEARBY_LOG(INFO, + "Cannot deserialize BluetoothDeviceName: " + "expected uwbAddress size to be %d bytes, got %" PRIu64, + expected_uwb_address_length, uwb_address_.size()); + + // Clear enpoint_id for validadity. + endpoint_id_.clear(); + return; } - - std::string endpoint_name(bluetooth_device_name_bytes_read_ptr, - actual_endpoint_name_length); - bluetooth_device_name_bytes_read_ptr += actual_endpoint_name_length; - - return MakePtr(new BluetoothDeviceName(Version::V1, pcp, endpoint_id, - scoped_service_id_hash.release(), - endpoint_name)); } - default: - // TODO(reznor): [ANALYTICIZE] This either represents corruption over the - // air, or older versions of GmsCore intermingling with newer ones. - - // TODO(reznor): logger.atDebug().log("Cannot deserialize - // BluetoothDeviceName: unsupported V1 PCP %d", pcp); - return Ptr(); } } -std::uint32_t BluetoothDeviceName::computeEndpointNameLength( - ConstPtr bluetooth_device_name_bytes) { - return kMaxEndpointNameLength - - (kMaxBluetoothDeviceNameLength - bluetooth_device_name_bytes->size()); -} - -std::uint32_t BluetoothDeviceName::computeBluetoothDeviceNameLength( - ConstPtr endpoint_name_bytes) { - return kMaxBluetoothDeviceNameLength - - (kMaxEndpointNameLength - endpoint_name_bytes->size()); -} - -Ptr BluetoothDeviceName::createV1Bytes( - PCP::Value pcp, const std::string& endpoint_id, - ConstPtr service_id_hash, - ConstPtr endpoint_name_bytes) { - std::uint32_t bluetooth_device_name_length = - computeBluetoothDeviceNameLength(endpoint_name_bytes); - Ptr bluetooth_device_name_bytes{ - new ByteArray{bluetooth_device_name_length}}; - - char* bluetooth_device_name_bytes_write_ptr = - bluetooth_device_name_bytes->getData(); - - // The first 3 bits are the Version. - char version_and_pcp_byte = - static_cast((Version::V1 << 5) & kVersionBitmask); - // The next 5 bits are the PCP. - version_and_pcp_byte |= static_cast(pcp & kPCPBitmask); - *bluetooth_device_name_bytes_write_ptr = version_and_pcp_byte; - bluetooth_device_name_bytes_write_ptr++; - - switch (pcp) { - case PCP::P2P_CLUSTER: // Fall through - case PCP::P2P_STAR: // Fall through - case PCP::P2P_POINT_TO_POINT: - // The next 32 bits are the endpoint_id. - if (endpoint_id.size() != kEndpointIdLength) { - // TODO(reznor): logger.atDebug().log("Cannot serialize - // BluetoothDeviceName: V1 Endpoint ID %s (%d bytes) should be exactly - // %d bytes", endpointId, endpointId.length(), ENDPOINT_ID_LENGTH); - return Ptr(); - } - memcpy(bluetooth_device_name_bytes_write_ptr, endpoint_id.data(), - kEndpointIdLength); - bluetooth_device_name_bytes_write_ptr += kEndpointIdLength; - - // The next 24 bits are the service_id_hash. - if (service_id_hash->size() != kServiceIdHashLength) { - // TODO(reznor): logger.atDebug().log("Cannot serialize - // BluetoothDeviceName: V1 ServiceID hash (%d bytes) should be exactly - // %d bytes", serviceIdHash.length, SERVICE_ID_HASH_LENGTH); - return Ptr(); - } - memcpy(bluetooth_device_name_bytes_write_ptr, service_id_hash->getData(), - kServiceIdHashLength); - bluetooth_device_name_bytes_write_ptr += kServiceIdHashLength; - - // The next 56 bits are reserved, and should all be zeroed out, so do - // that and then jump over 56 bits to position things for the next write. - memset(bluetooth_device_name_bytes_write_ptr, 0, kReservedLength); - bluetooth_device_name_bytes_write_ptr += kReservedLength; - - // The next 8 bits are the length of the endpoint_name. - *bluetooth_device_name_bytes_write_ptr = static_cast( - endpoint_name_bytes->size() & kEndpointNameLengthBitmask); - bluetooth_device_name_bytes_write_ptr++; - - // The remaining bits are filled with the endpoint_name. - memcpy(bluetooth_device_name_bytes_write_ptr, - endpoint_name_bytes->getData(), endpoint_name_bytes->size()); - bluetooth_device_name_bytes_write_ptr += endpoint_name_bytes->size(); - - break; - default: - // TODO(reznor): logger.atDebug().log("Cannot serialize - // BluetoothDeviceName: unsupported V1 PCP %d", pcp); - return Ptr(); +BluetoothDeviceName::operator std::string() const { + if (!IsValid()) { + return ""; } - return bluetooth_device_name_bytes; -} + // The upper 3 bits are the Version. + auto version_and_pcp_byte = static_cast( + (static_cast(Version::kV1) << 5) & kVersionBitmask); + // The lower 5 bits are the PCP. + version_and_pcp_byte |= + static_cast(static_cast(pcp_) & kPcpBitmask); -BluetoothDeviceName::BluetoothDeviceName(Version::Value version, PCP::Value pcp, - const std::string& endpoint_id, - ConstPtr service_id_hash, - const std::string& endpoint_name) - : version_(version), - pcp_(pcp), - endpoint_id_(endpoint_id), - service_id_hash_(service_id_hash), - endpoint_name_(endpoint_name) {} + // A byte contains WebRtcState state. + int web_rtc_connectable_flag = + (web_rtc_state_ == WebRtcState::kConnectable) ? 1 : 0; + char field_byte = static_cast(web_rtc_connectable_flag) & + kWebRtcConnectableFlagBitmask; -BluetoothDeviceName::~BluetoothDeviceName() { - // Nothing to do. -} + ByteArray reserved_bytes{kReservedLength}; -BluetoothDeviceName::Version::Value BluetoothDeviceName::getVersion() const { - return version_; -} + ByteArray usable_endpoint_info(endpoint_info_); + if (endpoint_info_.size() > kMaxEndpointInfoLength) { + NEARBY_LOG(INFO, + "While serializing Advertisement, truncating Endpoint Name %s " + "(%lu bytes) down to %d bytes", + absl::BytesToHexString(endpoint_info_.data()).c_str(), + endpoint_info_.size(), kMaxEndpointInfoLength); + usable_endpoint_info.SetData(endpoint_info_.data(), kMaxEndpointInfoLength); + } -PCP::Value BluetoothDeviceName::getPCP() const { return pcp_; } + // clang-format off + std::string out = absl::StrCat(std::string(1, version_and_pcp_byte), + endpoint_id_, + std::string(service_id_hash_), + std::string(1, field_byte), + std::string(reserved_bytes), + std::string(1, usable_endpoint_info.size()), + std::string(usable_endpoint_info)); + // clang-format on -std::string BluetoothDeviceName::getEndpointId() const { return endpoint_id_; } + // If UWB address is available, attach it at the end. + if (!uwb_address_.Empty()) { + absl::StrAppend(&out, std::string(1, uwb_address_.size())); + absl::StrAppend(&out, std::string(uwb_address_)); + } -ConstPtr BluetoothDeviceName::getServiceIdHash() const { - return service_id_hash_.get(); -} - -std::string BluetoothDeviceName::getEndpointName() const { - return endpoint_name_; + return Base64Utils::Encode(ByteArray{std::move(out)}); } } // namespace connections diff --git a/cpp/core/internal/bluetooth_device_name.h b/cpp/core/internal/bluetooth_device_name.h index de81dee7..859fe480 100644 --- a/cpp/core/internal/bluetooth_device_name.h +++ b/cpp/core/internal/bluetooth_device_name.h @@ -3,10 +3,10 @@ #include +#include "core/internal/base_pcp_handler.h" #include "core/internal/pcp.h" -#include "platform/byte_array.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "platform/base/byte_array.h" +#include "absl/strings/string_view.h" namespace location { namespace nearby { @@ -19,64 +19,58 @@ namespace connections { class BluetoothDeviceName { public: // Versions of the BluetoothDeviceName. - struct Version { - enum Value { - V1 = 1, - // Version is only allocated 3 bits in the BluetoothDeviceName, so this - // can never go beyond V7. - }; + enum class Version { + kUndefined = 0, + kV1 = 1, + // Version is only allocated 3 bits in the BluetoothDeviceName, so this + // can never go beyond V7. }; - static Ptr fromString( - const std::string& bluetooth_device_name_string); + static constexpr int kServiceIdHashLength = 3; - static std::string asString(Version::Value version, PCP::Value pcp, - const std::string& endpoint_id, - ConstPtr service_id_hash, - const std::string& endpoint_name); + BluetoothDeviceName() = default; + BluetoothDeviceName(Version version, Pcp pcp, absl::string_view endpoint_id, + const ByteArray& service_id_hash, + const ByteArray& endpoint_info, + const ByteArray& uwb_address, + WebRtcState web_rtc_state); + explicit BluetoothDeviceName(absl::string_view bluetooth_device_name_string); + BluetoothDeviceName(const BluetoothDeviceName&) = default; + BluetoothDeviceName& operator=(const BluetoothDeviceName&) = default; + BluetoothDeviceName(BluetoothDeviceName&&) = default; + BluetoothDeviceName& operator=(BluetoothDeviceName&&) = default; + ~BluetoothDeviceName() = default; - static const std::uint32_t kServiceIdHashLength; + explicit operator std::string() const; - ~BluetoothDeviceName(); - - Version::Value getVersion() const; - PCP::Value getPCP() const; - std::string getEndpointId() const; - ConstPtr getServiceIdHash() const; - std::string getEndpointName() const; + bool IsValid() const { return !endpoint_id_.empty(); } + Version GetVersion() const { return version_; } + Pcp GetPcp() const { return pcp_; } + std::string GetEndpointId() const { return endpoint_id_; } + ByteArray GetServiceIdHash() const { return service_id_hash_; } + ByteArray GetEndpointInfo() const { return endpoint_info_; } + ByteArray GetUwbAddress() const { return uwb_address_; } + WebRtcState GetWebRtcState() const { return web_rtc_state_; } private: - static Ptr createV1BluetoothDeviceName( - ConstPtr bluetooth_device_name_bytes); - static std::uint32_t computeEndpointNameLength( - ConstPtr bluetooth_device_name_bytes); - static std::uint32_t computeBluetoothDeviceNameLength( - ConstPtr endpoint_name_bytes); - static Ptr createV1Bytes(PCP::Value pcp, - const std::string& endpoint_id, - ConstPtr service_id_hash, - ConstPtr endpoint_name_bytes); + static constexpr int kEndpointIdLength = 4; + static constexpr int kReservedLength = 6; + static constexpr int kMaxEndpointInfoLength = 131; + static constexpr int kMinBluetoothDeviceNameLength = 16; - static const std::uint32_t kMaxBluetoothDeviceNameLength; - static const std::uint32_t kEndpointIdLength; - static const std::uint32_t kReservedLength; - static const std::uint32_t kMaxEndpointNameLength; - static const std::uint32_t kMinBluetoothDeviceNameLength; + static constexpr int kVersionBitmask = 0x0E0; + static constexpr int kPcpBitmask = 0x01F; + static constexpr int kEndpointNameLengthBitmask = 0x0FF; + static constexpr int kWebRtcConnectableFlagBitmask = 0x01; - static const std::uint16_t kVersionBitmask; - static const std::uint16_t kPCPBitmask; - static const std::uint16_t kEndpointNameLengthBitmask; - - BluetoothDeviceName(Version::Value version, PCP::Value pcp, - const std::string& endpoint_id, - ConstPtr service_id_hash, - const std::string& endpoint_name); - - const Version::Value version_; - const PCP::Value pcp_; - const std::string endpoint_id_; - ScopedPtr > service_id_hash_; - const std::string endpoint_name_; + Version version_{Version::kUndefined}; + Pcp pcp_{Pcp::kUnknown}; + std::string endpoint_id_; + ByteArray service_id_hash_; + ByteArray endpoint_info_; + // TODO(b/169550050): Define UWB address field. + ByteArray uwb_address_; + WebRtcState web_rtc_state_{WebRtcState::kUndefined}; }; } // namespace connections diff --git a/cpp/core/internal/bluetooth_device_name_test.cc b/cpp/core/internal/bluetooth_device_name_test.cc index 90a789ea..31d456e5 100644 --- a/cpp/core/internal/bluetooth_device_name_test.cc +++ b/cpp/core/internal/bluetooth_device_name_test.cc @@ -1,9 +1,9 @@ #include "core/internal/bluetooth_device_name.h" #include +#include -#include "platform/base64_utils.h" -#include "platform/port/string.h" +#include "platform/base/base64_utils.h" #include "gtest/gtest.h" namespace location { @@ -11,185 +11,216 @@ namespace nearby { namespace connections { namespace { -const BluetoothDeviceName::Version::Value version = - BluetoothDeviceName::Version::V1; -const PCP::Value pcp = PCP::P2P_CLUSTER; -const char endpoint_id[] = "AB12"; -const char service_id_hash_bytes[] = {0x0A, 0x0B, 0x0C}; -const char endpoint_name[] = "RAWK + ROWL!"; +constexpr BluetoothDeviceName::Version kVersion = + BluetoothDeviceName::Version::kV1; +constexpr Pcp kPcp = Pcp::kP2pCluster; +constexpr absl::string_view kEndPointID{"AB12"}; +constexpr absl::string_view kServiceIDHashBytes{"\x0a\x0b\x0c"}; +constexpr absl::string_view kEndPointName{"RAWK + ROWL!"}; +constexpr WebRtcState kWebRtcState = WebRtcState::kConnectable; -TEST(BluetoothDeviceNameTest, SerializationDeserializationWorks) { - ScopedPtr > scoped_service_id_hash(new ByteArray( - service_id_hash_bytes, sizeof(service_id_hash_bytes) / sizeof(char))); +// TODO(b/169550050): Implement UWBAddress. +TEST(BluetoothDeviceNameTest, ConstructionWorks) { + ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; + ByteArray endpoint_info{std::string(kEndPointName)}; + BluetoothDeviceName bluetooth_device_name{kVersion, + kPcp, + kEndPointID, + service_id_hash, + endpoint_info, + ByteArray{}, + kWebRtcState}; - std::string bluetooth_device_name_string = BluetoothDeviceName::asString( - version, pcp, endpoint_id, ConstifyPtr(scoped_service_id_hash.get()), - endpoint_name); - ScopedPtr > scoped_bluetooth_device_name( - BluetoothDeviceName::fromString(bluetooth_device_name_string)); - - ASSERT_EQ(pcp, scoped_bluetooth_device_name->getPCP()); - ASSERT_EQ(version, scoped_bluetooth_device_name->getVersion()); - ASSERT_EQ(endpoint_id, scoped_bluetooth_device_name->getEndpointId()); - ASSERT_EQ(sizeof(service_id_hash_bytes) / sizeof(char), - scoped_bluetooth_device_name->getServiceIdHash()->size()); - ASSERT_EQ(0, - memcmp(service_id_hash_bytes, - scoped_bluetooth_device_name->getServiceIdHash()->getData(), - scoped_bluetooth_device_name->getServiceIdHash()->size())); - ASSERT_EQ(endpoint_name, scoped_bluetooth_device_name->getEndpointName()); + EXPECT_TRUE(bluetooth_device_name.IsValid()); + EXPECT_EQ(kVersion, bluetooth_device_name.GetVersion()); + EXPECT_EQ(kPcp, bluetooth_device_name.GetPcp()); + EXPECT_EQ(kEndPointID, bluetooth_device_name.GetEndpointId()); + EXPECT_EQ(service_id_hash, bluetooth_device_name.GetServiceIdHash()); + EXPECT_EQ(endpoint_info, bluetooth_device_name.GetEndpointInfo()); + EXPECT_EQ(kWebRtcState, bluetooth_device_name.GetWebRtcState()); } -TEST(BluetoothDeviceNameTest, - SerializationDeserializationWorksWithEmptyEndpointName) { - std::string empty_endpoint_name; +TEST(BluetoothDeviceNameTest, ConstructionWorksWithEmptyEndpointName) { + ByteArray empty_endpoint_info; - ScopedPtr > scoped_service_id_hash(new ByteArray( - service_id_hash_bytes, sizeof(service_id_hash_bytes) / sizeof(char))); + ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; + BluetoothDeviceName bluetooth_device_name{kVersion, + kPcp, + kEndPointID, + service_id_hash, + empty_endpoint_info, + ByteArray{}, + kWebRtcState}; - std::string bluetooth_device_name_string = BluetoothDeviceName::asString( - version, pcp, endpoint_id, ConstifyPtr(scoped_service_id_hash.get()), - empty_endpoint_name); - ScopedPtr > scoped_bluetooth_device_name( - BluetoothDeviceName::fromString(bluetooth_device_name_string)); - - ASSERT_EQ(pcp, scoped_bluetooth_device_name->getPCP()); - ASSERT_EQ(version, scoped_bluetooth_device_name->getVersion()); - ASSERT_EQ(endpoint_id, scoped_bluetooth_device_name->getEndpointId()); - ASSERT_EQ(sizeof(service_id_hash_bytes) / sizeof(char), - scoped_bluetooth_device_name->getServiceIdHash()->size()); - ASSERT_EQ(0, - memcmp(service_id_hash_bytes, - scoped_bluetooth_device_name->getServiceIdHash()->getData(), - scoped_bluetooth_device_name->getServiceIdHash()->size())); - ASSERT_EQ(empty_endpoint_name, - scoped_bluetooth_device_name->getEndpointName()); + EXPECT_TRUE(bluetooth_device_name.IsValid()); + EXPECT_EQ(kVersion, bluetooth_device_name.GetVersion()); + EXPECT_EQ(kPcp, bluetooth_device_name.GetPcp()); + EXPECT_EQ(kEndPointID, bluetooth_device_name.GetEndpointId()); + EXPECT_EQ(service_id_hash, bluetooth_device_name.GetServiceIdHash()); + EXPECT_EQ(empty_endpoint_info, bluetooth_device_name.GetEndpointInfo()); + EXPECT_EQ(kWebRtcState, bluetooth_device_name.GetWebRtcState()); } -TEST(BluetoothDeviceNameTest, SerializationFailsWithBadVersion) { - BluetoothDeviceName::Version::Value bad_version = - static_cast(666); +TEST(BluetoothDeviceNameTest, ConstructionFailsWithBadVersion) { + auto bad_version = static_cast(666); - ScopedPtr > scoped_service_id_hash(new ByteArray( - service_id_hash_bytes, sizeof(service_id_hash_bytes) / sizeof(char))); + ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; + ByteArray endpoint_info{std::string(kEndPointName)}; + BluetoothDeviceName bluetooth_device_name{bad_version, + kPcp, + kEndPointID, + service_id_hash, + endpoint_info, + ByteArray{}, + kWebRtcState}; - std::string bluetooth_device_name_string = BluetoothDeviceName::asString( - bad_version, pcp, endpoint_id, ConstifyPtr(scoped_service_id_hash.get()), - endpoint_name); - - ASSERT_TRUE(bluetooth_device_name_string.empty()); + EXPECT_FALSE(bluetooth_device_name.IsValid()); } -TEST(BluetoothDeviceNameTest, SerializationFailsWithBadPCP) { - PCP::Value bad_pcp = static_cast(666); +TEST(BluetoothDeviceNameTest, ConstructionFailsWithBadPcp) { + auto bad_pcp = static_cast(666); - ScopedPtr > scoped_service_id_hash(new ByteArray( - service_id_hash_bytes, sizeof(service_id_hash_bytes) / sizeof(char))); + ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; + ByteArray endpoint_info{std::string(kEndPointName)}; + BluetoothDeviceName bluetooth_device_name{kVersion, + bad_pcp, + kEndPointID, + service_id_hash, + endpoint_info, + ByteArray{}, + kWebRtcState}; - std::string bluetooth_device_name_string = BluetoothDeviceName::asString( - version, bad_pcp, endpoint_id, ConstifyPtr(scoped_service_id_hash.get()), - endpoint_name); - - ASSERT_TRUE(bluetooth_device_name_string.empty()); + EXPECT_FALSE(bluetooth_device_name.IsValid()); } -TEST(BluetoothDeviceNameTest, SerializationFailsWithShortEndpointId) { +TEST(BluetoothDeviceNameTest, ConstructionFailsWithShortEndpointId) { std::string short_endpoint_id("AB1"); - ScopedPtr > scoped_service_id_hash(new ByteArray( - service_id_hash_bytes, sizeof(service_id_hash_bytes) / sizeof(char))); + ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; + ByteArray endpoint_info{std::string(kEndPointName)}; + BluetoothDeviceName bluetooth_device_name{kVersion, + kPcp, + short_endpoint_id, + service_id_hash, + endpoint_info, + ByteArray{}, + kWebRtcState}; - std::string bluetooth_device_name_string = BluetoothDeviceName::asString( - version, pcp, short_endpoint_id, - ConstifyPtr(scoped_service_id_hash.get()), endpoint_name); - - ASSERT_TRUE(bluetooth_device_name_string.empty()); + EXPECT_FALSE(bluetooth_device_name.IsValid()); } -TEST(BluetoothDeviceNameTest, SerializationFailsWithLongEndpointId) { +TEST(BluetoothDeviceNameTest, ConstructionFailsWithLongEndpointId) { std::string long_endpoint_id("AB12X"); - ScopedPtr > scoped_service_id_hash(new ByteArray( - service_id_hash_bytes, sizeof(service_id_hash_bytes) / sizeof(char))); + ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; + ByteArray endpoint_info{std::string(kEndPointName)}; + BluetoothDeviceName bluetooth_device_name{kVersion, + kPcp, + long_endpoint_id, + service_id_hash, + endpoint_info, + ByteArray{}, + kWebRtcState}; - std::string bluetooth_device_name_string = BluetoothDeviceName::asString( - version, pcp, long_endpoint_id, ConstifyPtr(scoped_service_id_hash.get()), - endpoint_name); - - ASSERT_TRUE(bluetooth_device_name_string.empty()); + EXPECT_FALSE(bluetooth_device_name.IsValid()); } -TEST(BluetoothDeviceNameTest, SerializationFailsWithShortServiceIdHash) { - char short_service_id_hash_bytes[] = {0x0A, 0x0B}; +TEST(BluetoothDeviceNameTest, ConstructionFailsWithShortServiceIdHash) { + char short_service_id_hash_bytes[] = "\x0a\x0b"; - ScopedPtr > scoped_short_service_id_hash( - new ByteArray(short_service_id_hash_bytes, - sizeof(short_service_id_hash_bytes) / sizeof(char))); + ByteArray short_service_id_hash{short_service_id_hash_bytes}; + ByteArray endpoint_info{std::string(kEndPointName)}; + BluetoothDeviceName bluetooth_device_name{kVersion, + kPcp, + kEndPointID, + short_service_id_hash, + endpoint_info, + ByteArray{}, + kWebRtcState}; - std::string bluetooth_device_name_string = BluetoothDeviceName::asString( - version, pcp, endpoint_id, - ConstifyPtr(scoped_short_service_id_hash.get()), endpoint_name); - - ASSERT_TRUE(bluetooth_device_name_string.empty()); + EXPECT_FALSE(bluetooth_device_name.IsValid()); } -TEST(BluetoothDeviceNameTest, SerializationFailsWithLongServiceIdHash) { - char long_service_id_hash_bytes[] = {0x0A, 0x0B, 0x0C, 0x0D}; +TEST(BluetoothDeviceNameTest, ConstructionFailsWithLongServiceIdHash) { + char long_service_id_hash_bytes[] = "\x0a\x0b\x0c\x0d"; - ScopedPtr > scoped_long_service_id_hash( - new ByteArray(long_service_id_hash_bytes, - sizeof(long_service_id_hash_bytes) / sizeof(char))); + ByteArray long_service_id_hash{long_service_id_hash_bytes}; + ByteArray endpoint_info{std::string(kEndPointName)}; + BluetoothDeviceName bluetooth_device_name{kVersion, + kPcp, + kEndPointID, + long_service_id_hash, + endpoint_info, + ByteArray{}, + kWebRtcState}; - std::string bluetooth_device_name_string = BluetoothDeviceName::asString( - version, pcp, endpoint_id, ConstifyPtr(scoped_long_service_id_hash.get()), - endpoint_name); - - ASSERT_TRUE(bluetooth_device_name_string.empty()); + EXPECT_FALSE(bluetooth_device_name.IsValid()); } -TEST(BluetoothDeviceNameTest, DeserializationFailsWithShortLength) { - char bluetooth_device_name_bytes[] = {'X'}; +TEST(BluetoothDeviceNameTest, ConstructionFailsWithShortStringLength) { + char bluetooth_device_name_string[] = "X"; - ScopedPtr > scoped_bluetooth_device_name_bytes( - new ByteArray(bluetooth_device_name_bytes, - sizeof(bluetooth_device_name_bytes) / sizeof(char))); + ByteArray bluetooth_device_name_bytes{bluetooth_device_name_string}; + BluetoothDeviceName bluetooth_device_name{ + Base64Utils::Encode(bluetooth_device_name_bytes)}; - ScopedPtr > scoped_bluetooth_device_name( - BluetoothDeviceName::fromString(Base64Utils::encode( - ConstifyPtr(scoped_bluetooth_device_name_bytes.get())))); - - ASSERT_TRUE(scoped_bluetooth_device_name.isNull()); + EXPECT_FALSE(bluetooth_device_name.IsValid()); } -TEST(BluetoothDeviceNameTest, DeserializationFailsWithWrongEndpointNameLength) { +TEST(BluetoothDeviceNameTest, ConstructionFailsWithWrongEndpointNameLength) { // Serialize good data into a good Bluetooth Device Name. - ScopedPtr > scoped_service_id_hash(new ByteArray( - service_id_hash_bytes, sizeof(service_id_hash_bytes) / sizeof(char))); - - std::string bluetooth_device_name_string = BluetoothDeviceName::asString( - version, pcp, endpoint_id, ConstifyPtr(scoped_service_id_hash.get()), - endpoint_name); + ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; + ByteArray endpoint_info{std::string(kEndPointName)}; + BluetoothDeviceName bluetooth_device_name{kVersion, + kPcp, + kEndPointID, + service_id_hash, + endpoint_info, + ByteArray{}, + kWebRtcState}; + auto bluetooth_device_name_string = std::string(bluetooth_device_name); // Base64-decode the good Bluetooth Device Name. - ScopedPtr > scoped_bluetooth_device_name_bytes( - Base64Utils::decode(bluetooth_device_name_string)); + ByteArray bluetooth_device_name_bytes = + Base64Utils::Decode(bluetooth_device_name_string); // Corrupt the EndpointNameLength bits (120-127) by reversing all of them. - std::string corrupt_bluetooth_device_name_bytes( - scoped_bluetooth_device_name_bytes->getData(), - scoped_bluetooth_device_name_bytes->size()); - corrupt_bluetooth_device_name_bytes[15] ^= 0x0FF; + std::string corrupt_string(bluetooth_device_name_bytes.data(), + bluetooth_device_name_bytes.size()); + corrupt_string[15] ^= 0x0FF; // Base64-encode the corrupted bytes into a corrupt Bluetooth Device Name. - ScopedPtr > scoped_corrupt_bluetooth_device_name_bytes( - new ByteArray(corrupt_bluetooth_device_name_bytes.data(), - corrupt_bluetooth_device_name_bytes.size())); - std::string corrupt_bluetooth_device_name_string(Base64Utils::encode( - ConstifyPtr(scoped_corrupt_bluetooth_device_name_bytes.get()))); + ByteArray corrupt_bluetooth_device_name_bytes{corrupt_string.data(), + corrupt_string.size()}; + std::string corrupt_bluetooth_device_name_string( + Base64Utils::Encode(corrupt_bluetooth_device_name_bytes)); // And deserialize the corrupt Bluetooth Device Name. - ScopedPtr > scoped_bluetooth_device_name( - BluetoothDeviceName::fromString(corrupt_bluetooth_device_name_string)); + BluetoothDeviceName corrupt_bluetooth_device_name( + corrupt_bluetooth_device_name_string); - ASSERT_TRUE(scoped_bluetooth_device_name.isNull()); + EXPECT_FALSE(corrupt_bluetooth_device_name.IsValid()); +} + +TEST(BluetoothDeviceNameTest, CanParseGeneratedName) { + ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; + ByteArray endpoint_info{std::string(kEndPointName)}; + // Build name1 from scratch. + BluetoothDeviceName name1{kVersion, + kPcp, + kEndPointID, + service_id_hash, + endpoint_info, + ByteArray{}, + kWebRtcState}; + // Build name2 from string composed from name1. + BluetoothDeviceName name2{std::string(name1)}; + EXPECT_TRUE(name1.IsValid()); + EXPECT_TRUE(name2.IsValid()); + EXPECT_EQ(name1.GetVersion(), name2.GetVersion()); + EXPECT_EQ(name1.GetPcp(), name2.GetPcp()); + EXPECT_EQ(name1.GetEndpointId(), name2.GetEndpointId()); + EXPECT_EQ(name1.GetServiceIdHash(), name2.GetServiceIdHash()); + EXPECT_EQ(name1.GetEndpointInfo(), name2.GetEndpointInfo()); + EXPECT_EQ(name1.GetWebRtcState(), name2.GetWebRtcState()); } } // namespace diff --git a/cpp/core/internal/bluetooth_endpoint_channel.cc b/cpp/core/internal/bluetooth_endpoint_channel.cc index 9fa8069a..63bf83bb 100644 --- a/cpp/core/internal/bluetooth_endpoint_channel.cc +++ b/cpp/core/internal/bluetooth_endpoint_channel.cc @@ -2,40 +2,41 @@ #include +#include "platform/public/bluetooth_classic.h" +#include "platform/public/logging.h" + namespace location { namespace nearby { namespace connections { -Ptr BluetoothEndpointChannel::createOutgoing( - Ptr > medium_manager, const string& channel_name, - Ptr bluetooth_socket) { - return MakePtr(new BluetoothEndpointChannel(channel_name, bluetooth_socket)); +namespace { + +OutputStream* GetOutputStreamOrNull(BluetoothSocket& socket) { + if (socket.GetRemoteDevice().IsValid()) return &socket.GetOutputStream(); + return nullptr; } -Ptr BluetoothEndpointChannel::createIncoming( - Ptr > medium_manager, const string& channel_name, - Ptr bluetooth_socket) { - return MakePtr(new BluetoothEndpointChannel(channel_name, bluetooth_socket)); +InputStream* GetInputStreamOrNull(BluetoothSocket& socket) { + if (socket.GetRemoteDevice().IsValid()) return &socket.GetInputStream(); + return nullptr; } +} // namespace + BluetoothEndpointChannel::BluetoothEndpointChannel( - const string& channel_name, Ptr bluetooth_socket) - : BaseEndpointChannel(channel_name, bluetooth_socket->getInputStream(), - bluetooth_socket->getOutputStream()), - bluetooth_socket_(bluetooth_socket) {} + const std::string& channel_name, BluetoothSocket socket) + : BaseEndpointChannel(channel_name, GetInputStreamOrNull(socket), + GetOutputStreamOrNull(socket)), + bluetooth_socket_(std::move(socket)) {} -BluetoothEndpointChannel::~BluetoothEndpointChannel() {} - -proto::connections::Medium BluetoothEndpointChannel::getMedium() { +proto::connections::Medium BluetoothEndpointChannel::GetMedium() const { return proto::connections::Medium::BLUETOOTH; } -void BluetoothEndpointChannel::closeImpl() { - Exception::Value exception = bluetooth_socket_->close(); - if (exception != Exception::NONE) { - if (exception == Exception::IO) { - // TODO(tracyzhou): Add logging. - } +void BluetoothEndpointChannel::CloseImpl() { + auto status = bluetooth_socket_.Close(); + if (!status.Ok()) { + NEARBY_LOG(INFO, "Failed to close BT socket: exception=%d", status.value); } } diff --git a/cpp/core/internal/bluetooth_endpoint_channel.h b/cpp/core/internal/bluetooth_endpoint_channel.h index 31c84216..ab67653c 100644 --- a/cpp/core/internal/bluetooth_endpoint_channel.h +++ b/cpp/core/internal/bluetooth_endpoint_channel.h @@ -1,41 +1,28 @@ #ifndef CORE_INTERNAL_BLUETOOTH_ENDPOINT_CHANNEL_H_ #define CORE_INTERNAL_BLUETOOTH_ENDPOINT_CHANNEL_H_ +#include + #include "core/internal/base_endpoint_channel.h" -#include "core/internal/medium_manager.h" -#include "platform/api/bluetooth_classic.h" -#include "platform/api/platform.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "platform/public/bluetooth_classic.h" #include "proto/connections_enums.pb.h" namespace location { namespace nearby { namespace connections { -class BluetoothEndpointChannel : public BaseEndpointChannel { +class BluetoothEndpointChannel final : public BaseEndpointChannel { public: - using Platform = platform::ImplementationPlatform; + // Creates both outgoing and incoming BT channels. + BluetoothEndpointChannel(const std::string& channel_name, + BluetoothSocket bluetooth_socket); - static Ptr createOutgoing( - Ptr > medium_manager, const string& channel_name, - Ptr bluetooth_socket); - static Ptr createIncoming( - Ptr > medium_manager, const string& channel_name, - Ptr bluetooth_socket); - - ~BluetoothEndpointChannel() override; - - proto::connections::Medium getMedium() override; - - protected: - void closeImpl() override; + proto::connections::Medium GetMedium() const override; private: - BluetoothEndpointChannel(const string& channel_name, - Ptr bluetooth_socket); + void CloseImpl() override; - ScopedPtr > bluetooth_socket_; + BluetoothSocket bluetooth_socket_; }; } // namespace connections diff --git a/cpp/core_v2/internal/bwu_handler.h b/cpp/core/internal/bwu_handler.h similarity index 87% rename from cpp/core_v2/internal/bwu_handler.h rename to cpp/core/internal/bwu_handler.h index d042f6ce..a3a4587b 100644 --- a/cpp/core_v2/internal/bwu_handler.h +++ b/cpp/core/internal/bwu_handler.h @@ -1,10 +1,10 @@ -#ifndef CORE_V2_INTERNAL_BWU_HANDLER_H_ -#define CORE_V2_INTERNAL_BWU_HANDLER_H_ +#ifndef CORE_INTERNAL_BWU_HANDLER_H_ +#define CORE_INTERNAL_BWU_HANDLER_H_ -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/endpoint_channel.h" -#include "core_v2/internal/offline_frames.h" -#include "platform_v2/public/count_down_latch.h" +#include "core/internal/client_proxy.h" +#include "core/internal/endpoint_channel.h" +#include "core/internal/offline_frames.h" +#include "platform/public/count_down_latch.h" #include "proto/connections_enums.pb.h" namespace location { @@ -71,4 +71,4 @@ class BwuHandler { } // namespace nearby } // namespace location -#endif // CORE_V2_INTERNAL_BWU_HANDLER_H_ +#endif // CORE_INTERNAL_BWU_HANDLER_H_ diff --git a/cpp/core_v2/internal/bwu_manager.cc b/cpp/core/internal/bwu_manager.cc similarity index 98% rename from cpp/core_v2/internal/bwu_manager.cc rename to cpp/core/internal/bwu_manager.cc index 595b9784..30bdb773 100644 --- a/cpp/core_v2/internal/bwu_manager.cc +++ b/cpp/core/internal/bwu_manager.cc @@ -1,13 +1,13 @@ -#include "core_v2/internal/bwu_manager.h" +#include "core/internal/bwu_manager.h" #include #include -#include "core_v2/internal/bwu_handler.h" -#include "core_v2/internal/offline_frames.h" -#include "core_v2/internal/webrtc_bwu_handler.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/public/count_down_latch.h" +#include "core/internal/bwu_handler.h" +#include "core/internal/offline_frames.h" +#include "core/internal/webrtc_bwu_handler.h" +#include "platform/base/byte_array.h" +#include "platform/public/count_down_latch.h" #include "proto/connections_enums.pb.h" #include "absl/functional/bind_front.h" #include "absl/time/time.h" @@ -653,6 +653,9 @@ std::vector BwuManager::StripOutUnavailableMediums( case Medium::WIFI_LAN: available = mediums_->GetWifiLan().IsAvailable(); break; + case Medium::WEB_RTC: + available = mediums_->GetWebRtc().IsAvailable(); + break; case Medium::BLUETOOTH: available = mediums_->GetBluetoothClassic().IsAvailable(); break; diff --git a/cpp/core/internal/bwu_manager.cc.orig b/cpp/core/internal/bwu_manager.cc.orig new file mode 100644 index 00000000..8e46b3b2 --- /dev/null +++ b/cpp/core/internal/bwu_manager.cc.orig @@ -0,0 +1,780 @@ +#include "core/internal/bwu_manager.h" + +#include +#include + +#include "core/internal/bluetooth_bwu_handler.h" +#include "core/internal/bwu_handler.h" +#include "core/internal/offline_frames.h" +#include "core/internal/webrtc_bwu_handler.h" +#include "platform/base/byte_array.h" +#include "platform/public/count_down_latch.h" +#include "proto/connections_enums.pb.h" +#include "absl/functional/bind_front.h" +#include "absl/time/time.h" + +namespace location { +namespace nearby { +namespace connections { + +using ::location::nearby::proto::connections::ConnectionAttemptResult; +using ::location::nearby::proto::connections::DisconnectionReason; + +BwuManager::BwuManager( + Mediums& mediums, EndpointManager& endpoint_manager, + EndpointChannelManager& channel_manager, + absl::flat_hash_map> handlers, + Config config) + : config_(config), + mediums_(&mediums), + endpoint_manager_(&endpoint_manager), + channel_manager_(&channel_manager) { + if (config_.bandwidth_upgrade_retry_delay == absl::ZeroDuration()) { + config_.bandwidth_upgrade_retry_delay = absl::Seconds(5); + } + if (config_.bandwidth_upgrade_retry_max_delay == absl::ZeroDuration()) { + config_.bandwidth_upgrade_retry_max_delay = absl::Seconds(10); + } + if (config_.allow_upgrade_to.All(false)) { + config_.allow_upgrade_to.web_rtc = true; + } + if (!handlers.empty()) { + handlers_ = std::move(handlers); + } else { + InitBwuHandlers(); + } + + // Register the offline frame processor. + endpoint_manager_->RegisterFrameProcessor( + V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION, this); +} + +void BwuManager::InitBwuHandlers() { + // Register the supported concrete BwuMedium implementations. + BwuHandler::BwuNotifications notifications{ + .incoming_connection_cb = + absl::bind_front(&BwuManager::OnIncomingConnection, this), + }; + if (config_.allow_upgrade_to.web_rtc) { + handlers_.emplace(Medium::WEB_RTC, + std::make_unique( + *mediums_, *channel_manager_, notifications)); + } + if (config_.allow_upgrade_to.bluetooth) { + handlers_.emplace(Medium::BLUETOOTH, + std::make_unique( + *mediums_, *channel_manager_, notifications)); + } +} + +void BwuManager::Shutdown() { + NEARBY_LOG(INFO, "Initiating shutdown of BwuManager."); + + endpoint_manager_->UnregisterFrameProcessor( + V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION, this); + + CountDownLatch latch(1); + + RunOnBwuManagerThread([this, &latch]() { + for (auto& item : previous_endpoint_channels_) { + EndpointChannel* channel = item.second.get(); + if (!channel) continue; + channel->Close(DisconnectionReason::SHUTDOWN); + } + + CancelAllRetryUpgradeAlarms(); + medium_ = Medium::UNKNOWN_MEDIUM; + for (auto& item : handlers_) { + BwuHandler& handler = *item.second; + handler.Revert(); + } + handlers_.clear(); + latch.CountDown(); + }); + + latch.Await(); + + // Stop all the ongoing Runnables (as gracefully as possible). + alarm_executor_.Shutdown(); + serial_executor_.Shutdown(); + + NEARBY_LOG(INFO, "BwuHandler has shut down."); +} + +// This is the point on the Initiator side where the +// medium_ is set. +void BwuManager::InitiateBwuForEndpoint(ClientProxy* client, + const std::string& endpoint_id, + Medium new_medium) { + RunOnBwuManagerThread([this, client, endpoint_id, new_medium]() { + Medium proposed_medium = ChooseBestUpgradeMedium( + client->GetUpgradeMediums(endpoint_id).GetMediums(true)); + if (new_medium != Medium::UNKNOWN_MEDIUM) { + proposed_medium = new_medium; + } + auto* handler = SetCurrentBwuHandler(proposed_medium); + + if (!handler) return; + + if (in_progress_upgrades_.contains(endpoint_id)) { + return; + } + + auto channel = channel_manager_->GetChannelForEndpoint(endpoint_id); + + if (channel == nullptr) { + return; + } + + // Ignore requests where the medium we're upgrading to is the medium we're + // already connected over. This can happen now that Bluetooth is both an + // advertising medium and a potential bandwidth upgrade, and will continue + // to be possible as we add other new advertising mediums like mDNS (WiFi + // LAN). Very specifically, this happens now when a device uses P2P_CLUSTER, + // connects over Bluetooth, and is not connected to LAN. Bluetooth is the + // best medium, and we attempt to upgrade from Bluetooth to Bluetooth. + if (medium_ == channel->GetMedium()) { + return; + } + + std::string service_id = client->GetServiceId(); + ByteArray bytes = handler->InitializeUpgradedMediumForEndpoint( + client, service_id, endpoint_id); + + // Because we grab the endpointChannel first thing, it is possible the + // endpointChannel is stale by the time we attempt to write over it. + if (bytes.Empty()) { + NEARBY_LOG(ERROR, + "Couldn't complete the upgrade for endpoint " + "%s to %d because it failed to initialize the " + "BWU_NEGOTIATION.UPGRADE_PATH_AVAILABLE OfflineFrame.", + endpoint_id.c_str(), medium_); + UpgradePathInfo info; + info.set_medium(parser::MediumToUpgradePathInfoMedium(medium_)); + + ProcessUpgradeFailureEvent(client, endpoint_id, info); + return; + } + if (!channel->Write(bytes).Ok()) { + NEARBY_LOG(ERROR, + "Couldn't complete the upgrade for endpoint %s to %d because " + "it failed to write the " + "BWU_NEGOTIATION.UPGRADE_PATH_AVAILABLE OfflineFrame.", + endpoint_id.c_str(), medium_); + return; + } + + NEARBY_LOG(INFO, + "Successfully wrote the BWU_NEGOTIATION.UPGRADE_PATH_AVAILABLE " + "OfflineFrame while upgrading endpoint %s to %d.", + endpoint_id.c_str(), medium_); + in_progress_upgrades_.emplace(endpoint_id, client); + }); +} + +void BwuManager::OnIncomingFrame(OfflineFrame& frame, + const std::string& endpoint_id, + ClientProxy* client, Medium medium) { + if (parser::GetFrameType(frame) != V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION) + return; + auto bwu_frame = frame.v1().bandwidth_upgrade_negotiation(); + CountDownLatch latch(1); + RunOnBwuManagerThread([this, client, endpoint_id, &bwu_frame, &latch]() { + OnBwuNegotiationFrame(client, bwu_frame, endpoint_id); + latch.CountDown(); + }); + latch.Await(); +} + +void BwuManager::OnEndpointDisconnect(ClientProxy* client, + const std::string& endpoint_id, + CountDownLatch* barrier) { + RunOnBwuManagerThread([this, client, endpoint_id, barrier]() { + if (medium_ == Medium::UNKNOWN_MEDIUM) { + barrier->CountDown(); + return; + } + + if (handler_) { + handler_->OnEndpointDisconnect(client, endpoint_id); + } + + auto item = previous_endpoint_channels_.extract(endpoint_id); + + if (!item.empty()) { + auto old_channel = item.mapped(); + if (old_channel != nullptr) { + old_channel->Close(DisconnectionReason::SHUTDOWN); + } + } + in_progress_upgrades_.erase(endpoint_id); + CancelRetryUpgradeAlarm(endpoint_id); + + successfully_upgraded_endpoints_.erase(endpoint_id); + + // If this was our very last endpoint: + // + // a) revert all the changes for currentBwuMedium. + // b) reset currentBwuMedium. + if (channel_manager_->GetConnectedEndpointsCount() <= 1) { + Revert(); + } + barrier->CountDown(); + }); +} + +BwuHandler* BwuManager::SetCurrentBwuHandler(Medium medium) { + handler_ = nullptr; + medium_ = medium; + if (medium != Medium::UNKNOWN_MEDIUM) { + auto item = handlers_.find(medium); + if (item != handlers_.end()) { + handler_ = item->second.get(); + } + } + return handler_; +} + +void BwuManager::Revert() { + if (handler_) { + handler_->Revert(); + medium_ = Medium::UNKNOWN_MEDIUM; + handler_ = nullptr; + } +} + +void BwuManager::OnBwuNegotiationFrame(ClientProxy* client, + const BwuNegotiationFrame& frame, + const string& endpoint_id) { + switch (frame.event_type()) { + case BwuNegotiationFrame::UPGRADE_PATH_AVAILABLE: + ProcessBwuPathAvailableEvent(client, endpoint_id, + frame.upgrade_path_info()); + break; + case BwuNegotiationFrame::UPGRADE_FAILURE: + ProcessUpgradeFailureEvent(client, endpoint_id, + frame.upgrade_path_info()); + break; + case BwuNegotiationFrame::LAST_WRITE_TO_PRIOR_CHANNEL: + ProcessLastWriteToPriorChannelEvent(client, endpoint_id); + break; + case BwuNegotiationFrame::SAFE_TO_CLOSE_PRIOR_CHANNEL: + ProcessSafeToClosePriorChannelEvent(client, endpoint_id); + break; + default: + break; + } +} + +void BwuManager::OnIncomingConnection( + ClientProxy* client, + std::unique_ptr mutable_connection) { + std::shared_ptr connection( + mutable_connection.release()); + RunOnBwuManagerThread([this, client, connection]() { + EndpointChannel* channel = connection->channel.get(); + if (channel == nullptr) { + connection->socket->Close(); + return; + } + + ClientIntroduction introduction; + if (!ReadClientIntroductionFrame(channel, introduction)) { + // This was never a fully EstablishedConnection, no need to provide a + // closure reason. + channel->Close(); + return; + } + + const std::string& endpoint_id = introduction.endpoint_id(); + auto item = in_progress_upgrades_.extract(endpoint_id); + if (item.empty()) return; + ClientProxy* mapped_client = item.mapped(); + CancelRetryUpgradeAlarm(endpoint_id); + if (mapped_client == nullptr) { + // This was never a fully EstablishedConnection, no need to provide a + // closure reason. + channel->Close(); + return; + } + + CHECK(client == mapped_client); + + // Use the introductory client information sent over to run the upgrade + // protocol. + RunUpgradeProtocol(mapped_client, endpoint_id, + std::move(connection->channel)); + }); +} + +void BwuManager::RunOnBwuManagerThread(Runnable runnable) { + serial_executor_.Execute(std::move(runnable)); +} + +void BwuManager::RunUpgradeProtocol( + ClientProxy* client, const std::string& endpoint_id, + std::unique_ptr new_channel) { + // First, register this new EndpointChannel as *the* EndpointChannel to use + // for this endpoint here onwards. NOTE: We pause this new EndpointChannel + // until we've completely drained the old EndpointChannel to avoid out of + // order reads on the other side. This is a consequence of using the same + // UKEY2 context for both the previous and new EndpointChannels. UKEY2 uses + // sequence numbers for writes and reads, and simultaneously sending Payloads + // on the new channel and control messages on the old channel cause the other + // side to read messages out of sequence + new_channel->Pause(); + auto old_channel = channel_manager_->GetChannelForEndpoint(endpoint_id); + if (!old_channel) return; + channel_manager_->ReplaceChannelForEndpoint(client, endpoint_id, + std::move(new_channel)); + + // Next, initiate a clean shutdown for the previous EndpointChannel used for + // this endpoint by telling the remote device that it will not receive any + // more writes over that EndpointChannel. + if (!old_channel->Write(parser::ForBwuLastWrite()).Ok()) { + return; + } + + // The remainder of this clean shutdown for the previous EndpointChannel will + // continue when we receive a corresponding + // BANDWIDTH_UPGRADE_NEGOTIATION.LAST_WRITE_TO_PRIOR_CHANNEL OfflineFrame from + // the remote device, so for now, just store that previous EndpointChannel. + previous_endpoint_channels_.emplace(endpoint_id, old_channel); + + // If we already read LAST_WRITE on the old endpoint channel, then we can + // safely close it now. + auto item = successfully_upgraded_endpoints_.extract(endpoint_id); + if (!item.empty()) { + ProcessLastWriteToPriorChannelEvent(client, endpoint_id); + } +} + +// Outgoing BWU session. +void BwuManager::ProcessBwuPathAvailableEvent( + ClientProxy* client, const string& endpoint_id, + const UpgradePathInfo& upgrade_path_info) { + Medium medium = + parser::UpgradePathInfoMediumToMedium(upgrade_path_info.medium()); + if (medium_ == Medium::UNKNOWN_MEDIUM) { + SetCurrentBwuHandler(medium); + } + // Check for the correct medium so we don't process an incorrect OfflineFrame. + if (medium != medium_) { + RunUpgradeFailedProtocol(client, endpoint_id, upgrade_path_info); + return; + } + + auto channel = ProcessBwuPathAvailableEventInternal(client, endpoint_id, + upgrade_path_info); + ConnectionAttemptResult connectionAttemptResult; + if (channel != nullptr) { + connectionAttemptResult = ConnectionAttemptResult::RESULT_SUCCESS; + } else { + connectionAttemptResult = ConnectionAttemptResult::RESULT_ERROR; + } + + if (channel == nullptr) { + RunUpgradeFailedProtocol(client, endpoint_id, upgrade_path_info); + return; + } + + RunUpgradeProtocol(client, endpoint_id, std::move(channel)); +} + +std::unique_ptr +BwuManager::ProcessBwuPathAvailableEventInternal( + ClientProxy* client, const string& endpoint_id, + const UpgradePathInfo& upgrade_path_info) { + std::unique_ptr channel = + handler_->CreateUpgradedEndpointChannel(client, client->GetServiceId(), + endpoint_id, upgrade_path_info); + if (!channel) { + return nullptr; + } + + // Write the requisite BANDWIDTH_UPGRADE_NEGOTIATION.CLIENT_INTRODUCTION as + // the first OfflineFrame on this new EndpointChannel. + if (!channel->Write(parser::ForBwuIntroduction(client->GetLocalEndpointId())) + .Ok()) { + // This was never a fully EstablishedConnection, no need to provide a + // closure reason. + channel->Close(); + + NEARBY_LOG( + ERROR, + "Failed to write BWU_NEGOTIATION.CLIENT_INTRODUCTION OfflineFrame to " + "newly-created EndpointChannel %s, aborting upgrade.", + channel->GetName().c_str()); + + return {}; + } + + NEARBY_LOG( + INFO, + "Successfully wrote BWU_NEGOTIATION.CLIENT_INTRODUCTION OfflineFrame to " + "newly-created EndpointChannel %s while upgrading endpoint %s.", + channel->GetName().c_str(), endpoint_id.c_str()); + + // Set the AnalyticsRecorder so that the future closure of this + // EndpointChannel will be recorded. + return channel; +} + +void BwuManager::RunUpgradeFailedProtocol( + ClientProxy* client, const std::string& endpoint_id, + const UpgradePathInfo& upgrade_path_info) { + // We attempted to connect to the new medium that the remote device has set up + // for us but we failed. We need to let the remote device know so that they + // can pick another medium for us to try. + std::shared_ptr channel = + channel_manager_->GetChannelForEndpoint(endpoint_id); + if (!channel) { + NEARBY_LOG(ERROR, + "Couldn't find a previous EndpointChannel for %s " + "when sending an upgrade failure frame, short-circuiting the " + "upgrade protocol.", + endpoint_id.c_str()); + return; + } + + // Report UPGRADE_FAILURE to the remote device. + if (!channel->Write(parser::ForBwuFailure(upgrade_path_info)).Ok()) { + channel->Close(DisconnectionReason::IO_ERROR); + + NEARBY_LOG( + ERROR, + "Failed to write BANDWIDTH_UPGRADE_NEGOTIATION.UPGRADE_FAILURE " + "OfflineFrame to endpoint %s, short-circuiting the upgrade protocol.", + endpoint_id.c_str()); + return; + } + + // And lastly, clean up our currentBwuMedium since we failed to + // utilize it anyways. + if (medium_ != Medium::UNKNOWN_MEDIUM) { + Revert(); + } +} + +bool BwuManager::ReadClientIntroductionFrame(EndpointChannel* channel, + ClientIntroduction& introduction) { + auto data = channel->Read(); + if (!data.ok()) return false; + auto transfer(parser::FromBytes(data.result())); + if (!transfer.ok()) return false; + OfflineFrame frame = transfer.result(); + if (!frame.has_v1() || !frame.v1().has_bandwidth_upgrade_negotiation()) + return false; + const auto& frame_intro = + frame.v1().bandwidth_upgrade_negotiation().client_introduction(); + introduction = frame_intro; + return true; +} + +void BwuManager::ProcessLastWriteToPriorChannelEvent( + ClientProxy* client, const std::string& endpoint_id) { + // By this point in the upgrade protocol, there is the guarantee that both + // involved endpoints have registered a new EndpointChannel with the + // EndpointChannelManager as the official channel for communication; given + // the way communication is structured in the EndpointManager, this means + // that all new writes are happening over that new EndpointChannel, but + // reads are still happening over this prior EndpointChannel (to avoid data + // loss). But now that we've received this definitive final write over that + // prior EndpointChannel, we can let the remote device that they can safely + // close their end of this now-dormant EndpointChannel. + EndpointChannel* previous_endpoint_channel = + previous_endpoint_channels_[endpoint_id].get(); + if (!previous_endpoint_channel) { + NEARBY_LOG( + ERROR, + "Received a BWU_NEGOTIATION.LAST_WRITE_TO_PRIOR_CHANNEL OfflineFrame " + "for unknown endpoint %s, can't complete the upgrade protocol.", + endpoint_id.c_str()); + + successfully_upgraded_endpoints_.emplace(endpoint_id); + return; + } + + if (!previous_endpoint_channel->Write(parser::ForBwuSafeToClose()).Ok()) { + previous_endpoint_channel->Close(DisconnectionReason::IO_ERROR); + // Remove this prior EndpointChannel from previous_endpoint_channels to + // avoid leaks. + previous_endpoint_channels_.erase(endpoint_id); + + NEARBY_LOG( + ERROR, + "Failed to write BWU_NEGOTIATION.SAFE_TO_CLOSE_PRIOR_CHANNEL " + "OfflineFrame to endpoint %s, short-circuiting the upgrade protocol.", + endpoint_id.c_str()); + return; + } + + // The upgrade protocol's clean shutdown of the prior EndpointChannel will + // conclude when we receive a corresponding + // BANDWIDTH_UPGRADE_NEGOTIATION.SAFE_TO_CLOSE_PRIOR_CHANNEL OfflineFrame + // from the remote device. +} + +void BwuManager::ProcessSafeToClosePriorChannelEvent( + ClientProxy* client, const std::string& endpoint_id) { + // By this point in the upgrade protocol, there's no more writes happening + // over the prior EndpointChannel, and the remote device has given us the + // go-ahead to close this EndpointChannel [1], so we can safely close it + // (and depend on the EndpointManager querying the EndpointChannelManager to + // start reading from the new EndpointChannel). + // + // [1] Which also implies that they've received our + // BANDWIDTH_UPGRADE_NEGOTIATION.LAST_WRITE_TO_PRIOR_CHANNEL OfflineFrame), + // so there can be no data loss, regardless of whether the EndpointChannel + // allows reads of queued, unread data after the EndpointChannel has been + // closed from the other end (as is the case with conventional TCP sockets) + // or not (as is the case with Android's Bluetooth sockets, where closing + // instantly throws an IOException on the remote device). + auto item = previous_endpoint_channels_.extract(endpoint_id); + auto& previous_endpoint_channel = item.mapped(); + if (previous_endpoint_channel == nullptr) { + NEARBY_LOG( + ERROR, + "Received a BWU_NEGOTIATION.SAFE_TO_CLOSE_PRIOR_CHANNEL OfflineFrame " + "for unknown endpoint %s, can't complete the upgrade protocol.", + endpoint_id.c_str()); + return; + } + + NEARBY_LOG(INFO, + "BwuManager successfully received a " + "BWU_NEGOTIATION.SAFE_TO_CLOSE_PRIOR_CHANNEL OfflineFrame while " + "trying to upgrade endpoint %s.", + endpoint_id.c_str()); + + // Wait for in-flight messages to reach their peers. + SystemClock::Sleep(absl::Seconds(1)); + previous_endpoint_channel->Close(DisconnectionReason::UPGRADED); + + // Now that the old channel has been drained, we can unpause the new channel + std::shared_ptr channel = + channel_manager_->GetChannelForEndpoint(endpoint_id); + + if (!channel) { + NEARBY_LOG(ERROR, + "Attempted to resume the current EndpointChannel with endpoint " + "%s, but none was found", + endpoint_id.c_str()); + return; + } + + channel->Resume(); + + // Report the success to the client + client->OnBandwidthChanged(endpoint_id, channel->GetMedium()); +} + +void BwuManager::ProcessUpgradeFailureEvent( + ClientProxy* client, const std::string& endpoint_id, + const UpgradePathInfo& upgrade_info) { + // The remote device failed to upgrade to the new medium we set up for them. + // That's alright! We'll just try the next available medium (if there is + // one). + in_progress_upgrades_.erase(endpoint_id); + + // The first thing we have to do is to replace our + // currentBwuMedium with the next best upgrade medium we share + // with the remote device. The catch is that we can only do this if we only + // have one connected endpoint. Otherwise, we'll end up disrupting our other + // connected peers. + if (channel_manager_->GetConnectedEndpointsCount() > 1) { + // We can't change the currentBwuMedium, so there are no more + // upgrade attempts for this endpoint. Sorry. + NEARBY_LOG( + ERROR, + "Failed to attempt a new bandwidth upgrade for endpoint %s because we " + "have other connected endpoints and can't try a new upgrade medium.", + endpoint_id.c_str()); + return; + } + + // Revert the existing upgrade medium for now. + if (medium_ != Medium::UNKNOWN_MEDIUM) { + Revert(); + } + + // Loop through the ordered list of upgrade mediums. One by one, remove the + // top element until we get to the medium we last attempted to upgrade to. + // The remainder of the list will contain the mediums we haven't attempted + // yet. + Medium last = parser::UpgradePathInfoMediumToMedium(upgrade_info.medium()); + std::vector all_possible_mediums = + client->GetUpgradeMediums(endpoint_id).GetMediums(true); + std::vector untried_mediums(all_possible_mediums); + for (Medium medium : all_possible_mediums) { + untried_mediums.erase(untried_mediums.begin()); + if (medium == last) { + break; + } + } + + RetryUpgradeMediums(client, endpoint_id, untried_mediums); +} + +void BwuManager::RetryUpgradeMediums(ClientProxy* client, + const std::string& endpoint_id, + std::vector upgrade_mediums) { + Medium next_medium = ChooseBestUpgradeMedium(upgrade_mediums); + + // If current medium is not WiFi and we have not succeeded with upgrading + // yet, retry upgrade. + Medium current_medium = GetEndpointMedium(endpoint_id); + if (current_medium != Medium::WIFI_LAN && + (next_medium == current_medium || next_medium == Medium::UNKNOWN_MEDIUM || + upgrade_mediums.empty())) { + RetryUpgradesAfterDelay(client, endpoint_id); + return; + } + + // Attempt to set the new upgrade medium. + if (!SetCurrentBwuHandler(next_medium)) { + NEARBY_LOG( + INFO, + "BwuManager failed to attempt a new bandwidth upgrade for endpoint %s " + "because we couldn't set a new bandwidth upgrade medium.", + endpoint_id.c_str()); + return; + } + + // Now that we've successfully picked a new upgrade medium to try, + // re-initiate the bandwidth upgrade. + NEARBY_LOG(INFO, + "BwuManager is attempting to upgrade endpoint %s again with a new " + " bandwidth upgrade medium.", + endpoint_id.c_str()); + InitiateBwuForEndpoint(client, endpoint_id); +} + +std::vector BwuManager::StripOutUnavailableMediums( + const std::vector& mediums) { + std::vector available_mediums; + for (Medium m : mediums) { + bool available = false; + switch (m) { + case Medium::WIFI_LAN: + available = mediums_->GetWifiLan().IsAvailable(); + break; + case Medium::WEB_RTC: + available = mediums_->GetWebRtc().IsAvailable(); + break; + case Medium::BLUETOOTH: + available = mediums_->GetBluetoothClassic().IsAvailable(); + break; + default: + break; + } + if (available) { + available_mediums.push_back(m); + } + } + return available_mediums; +} + +// Returns the optimal medium supported by both devices. +// Each medium in the passed in list is checked for its availability with the +// medium_manager_ to ensure that the chosen upgrade medium is supported and +// available locally before continuing the upgrade. Once we pick a medium, all +// future connections will use it too. eg. If we chose Wifi LAN, we'll attempt +// to upgrade the 2nd, 3rd, etc remote endpoints with Wifi LAN even if they're +// on a different network (or had a better medium). This is a quick and easy +// way to prevent mediums, like Wifi Hotspot, from interfering with active +// connections (although it's suboptimal for bandwidth throughput). When all +// endpoints disconnect, we reset the bandwidth upgrade medium. +Medium BwuManager::ChooseBestUpgradeMedium(const std::vector& mediums) { + auto available_mediums = StripOutUnavailableMediums(mediums); + if (medium_ == Medium::UNKNOWN_MEDIUM) { + if (!available_mediums.empty()) { + // Case 1: This is our first time upgrading, and we have at least one + // supported medium to choose from. Return the first medium in the list, + // since they are ordered by preference. + return available_mediums[0]; + } + // Case 2: This is our first time upgrading, but there are no available + // upgrade mediums. Fall through to returning UNKNOWN_MEDIUM at the + // bottom. + NEARBY_LOG( + INFO, + "Current upgrade medium is unset, but there are no common supported " + "upgrade mediums."); + } else { + // Case 3: We have already upgraded, and there is a list of supported + // mediums to check against. Return the current upgrade medium if it's in + // the supported list. + if (std::find(available_mediums.begin(), available_mediums.end(), + medium_) != available_mediums.end()) { + return medium_; + } + // Case 4: We have already upgraded, but the current medium is not + // supported by the remote endpoint (it's not in the list, or the list is + // empty). Fall through and return Medium.UNKNOWN_MEDIUM because we cannot + // continue with the current upgrade medium, and we are not allowed to + // switch. + NEARBY_LOG( + INFO, + "Current upgrade medium %d is not supported by the remote endpoint", + medium_); + } + + return Medium::UNKNOWN_MEDIUM; +} + +void BwuManager::RetryUpgradesAfterDelay(ClientProxy* client, + const std::string& endpoint_id) { + absl::Duration delay = CalculateNextRetryDelay(endpoint_id); + CancelRetryUpgradeAlarm(endpoint_id); + CancelableAlarm alarm( + "BWU alarm", + [this, client, endpoint_id]() { + RunOnBwuManagerThread([this, client, endpoint_id]() { + if (!client->IsConnectedToEndpoint(endpoint_id)) { + return; + } + RetryUpgradeMediums( + client, endpoint_id, + client->GetUpgradeMediums(endpoint_id).GetMediums(true)); + }); + }, + delay, &alarm_executor_); + + retry_upgrade_alarms_.emplace(endpoint_id, + std::make_pair(std::move(alarm), delay)); + NEARBY_LOGS(INFO) << "Retry bandwidth upgrade after " << delay; +} + +absl::Duration BwuManager::CalculateNextRetryDelay( + const std::string& endpoint_id) { + auto item = retry_upgrade_alarms_.find(endpoint_id); + auto initial_delay = config_.bandwidth_upgrade_retry_delay; + auto delay = item == retry_upgrade_alarms_.end() + ? initial_delay + : item->second.second + initial_delay; + return std::min(delay, config_.bandwidth_upgrade_retry_max_delay); +} + +void BwuManager::CancelRetryUpgradeAlarm(const std::string& endpoint_id) { + auto item = retry_upgrade_alarms_.extract(endpoint_id); + if (item.empty()) return; + auto& pair = item.mapped(); + pair.first.Cancel(); +} + +void BwuManager::CancelAllRetryUpgradeAlarms() { + for (const auto& item : retry_upgrade_alarms_) { + const std::string& endpoint_id = item.first; + CancelRetryUpgradeAlarm(endpoint_id); + } +} + +Medium BwuManager::GetEndpointMedium(const std::string& endpoint_id) { + auto channel = channel_manager_->GetChannelForEndpoint(endpoint_id); + return channel == nullptr ? Medium::UNKNOWN_MEDIUM : channel->GetMedium(); +} + +} // namespace connections +} // namespace nearby +} // namespace location diff --git a/cpp/core_v2/internal/bwu_manager.h b/cpp/core/internal/bwu_manager.h similarity index 94% rename from cpp/core_v2/internal/bwu_manager.h rename to cpp/core/internal/bwu_manager.h index 0cb94df9..0cc73c84 100644 --- a/cpp/core_v2/internal/bwu_manager.h +++ b/cpp/core/internal/bwu_manager.h @@ -1,18 +1,18 @@ -#ifndef CORE_V2_INTERNAL_BWU_MANAGER_H_ -#define CORE_V2_INTERNAL_BWU_MANAGER_H_ +#ifndef CORE_INTERNAL_BWU_MANAGER_H_ +#define CORE_INTERNAL_BWU_MANAGER_H_ #include #include #include -#include "core_v2/internal/bwu_handler.h" -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/endpoint_manager.h" -#include "core_v2/internal/mediums/mediums.h" -#include "core_v2/options.h" +#include "core/internal/bwu_handler.h" +#include "core/internal/client_proxy.h" +#include "core/internal/endpoint_manager.h" +#include "core/internal/mediums/mediums.h" +#include "core/options.h" #include "proto/connections/offline_wire_formats.pb.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/public/scheduled_executor.h" +#include "platform/base/byte_array.h" +#include "platform/public/scheduled_executor.h" #include "proto/connections_enums.pb.h" #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" @@ -175,4 +175,4 @@ class BwuManager : public EndpointManager::FrameProcessor { } // namespace nearby } // namespace location -#endif // CORE_V2_INTERNAL_BWU_MANAGER_H_ +#endif // CORE_INTERNAL_BWU_MANAGER_H_ diff --git a/cpp/core_v2/internal/bwu_manager_test.cc b/cpp/core/internal/bwu_manager_test.cc similarity index 77% rename from cpp/core_v2/internal/bwu_manager_test.cc rename to cpp/core/internal/bwu_manager_test.cc index c130c239..00556c08 100644 --- a/cpp/core_v2/internal/bwu_manager_test.cc +++ b/cpp/core/internal/bwu_manager_test.cc @@ -1,11 +1,11 @@ -#include "core_v2/internal/bwu_manager.h" +#include "core/internal/bwu_manager.h" #include -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/endpoint_channel_manager.h" -#include "core_v2/internal/endpoint_manager.h" -#include "core_v2/internal/mediums/mediums.h" +#include "core/internal/client_proxy.h" +#include "core/internal/endpoint_channel_manager.h" +#include "core/internal/endpoint_manager.h" +#include "core/internal/mediums/mediums.h" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/cpp/core/internal/client_proxy.cc b/cpp/core/internal/client_proxy.cc index 55d6ea7f..93081562 100644 --- a/cpp/core/internal/client_proxy.cc +++ b/cpp/core/internal/client_proxy.cc @@ -2,587 +2,522 @@ #include #include -#include #include -#include "platform/api/hash_utils.h" -#include "platform/base64_utils.h" -#include "platform/prng.h" -#include "platform/synchronized.h" +#include "platform/base/base64_utils.h" +#include "platform/base/prng.h" +#include "platform/public/crypto.h" +#include "platform/public/logging.h" +#include "platform/public/mutex_lock.h" #include "proto/connections_enums.pb.h" +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" +#include "absl/strings/escaping.h" +#include "absl/strings/str_cat.h" namespace location { namespace nearby { namespace connections { -namespace client_proxy { +ClientProxy::ClientProxy() : client_id_(Prng().NextInt64()) {} -template -void eraseOwnedPtrFromMap(std::map>& m, const K& k) { - typename std::map>::iterator it = m.find(k); - if (it != m.end()) { - it->second.destroy(); - m.erase(it); +ClientProxy::~ClientProxy() { Reset(); } + +std::int64_t ClientProxy::GetClientId() const { return client_id_; } + +std::string ClientProxy::GetLocalEndpointId() { + if (local_endpoint_id_.empty()) { + // 1) Concatenate the Random 64-bit value with "client" string. + // 2) Compute a hash of that concatenation. + // 3) Base64-encode that hash, to make it human-readable. + // 4) Use only the first kEndpointIdLength bytes to make ID. + ByteArray id_hash = + Crypto::Sha256(absl::StrCat("client", prng_.NextInt64())); + std::string id = Base64Utils::Encode(id_hash).substr(0, kEndpointIdLength); + NEARBY_LOG( + INFO, + "ClientProxy [Local Endpoint Generated]: client=%p; endpoint_id=%s", + this, id.c_str()); + local_endpoint_id_ = id; } + return local_endpoint_id_; } -} // namespace client_proxy +void ClientProxy::Reset() { + MutexLock lock(&mutex_); -template -const std::int32_t ClientProxy::kEndpointIdLength = 4; - -template -ClientProxy::ClientProxy() - : lock_(Platform::createLock()), client_id_(Prng().nextInt64()) {} - -template -ClientProxy::~ClientProxy() { - reset(); + StoppedAdvertising(); + StoppedDiscovery(); + RemoveAllEndpoints(); } -template -std::int64_t ClientProxy::getClientId() const { - return client_id_; +void ClientProxy::StartedAdvertising( + const std::string& service_id, Strategy strategy, + const ConnectionListener& listener, + absl::Span mediums) { + MutexLock lock(&mutex_); + + if (connections_.empty()) local_endpoint_id_.clear(); + advertising_info_ = {service_id, listener}; } -template -std::string ClientProxy::generateLocalEndpointId() { - // 1) Concatenate the DeviceID with this ClientID. - // 2) Compute a hash of that concatenation. - // 3) Base64-encode that hash, to make it human-readable. - // 4) Use only the first 4 bytes of that Base64 encoding. +void ClientProxy::StoppedAdvertising() { + MutexLock lock(&mutex_); - std::ostringstream client_id_str; - client_id_str << getClientId(); - - ScopedPtr> hash_utils(Platform::createHashUtils()); - ScopedPtr> id_hash( - hash_utils->sha256(Platform::getDeviceId() + client_id_str.str())); - - return Base64Utils::encode(id_hash.get()).substr(0, kEndpointIdLength); -} - -template -void ClientProxy::reset() { - Synchronized s(lock_.get()); - - stoppedAdvertising(); - stoppedDiscovery(); - removeAllEndpoints(); -} - -template -void ClientProxy::startedAdvertising( - const std::string& service_id, const Strategy& strategy, - Ptr connection_lifecycle_listener, - const std::vector& mediums) { - Synchronized s(lock_.get()); - - advertising_info_.destroy(); - advertising_info_ = - MakePtr(new AdvertisingInfo(service_id, connection_lifecycle_listener)); -} - -template -void ClientProxy::stoppedAdvertising() { - Synchronized s(lock_.get()); - - if (isAdvertising()) { - advertising_info_.destroy(); + if (IsAdvertising()) { + advertising_info_.Clear(); } + if (connections_.empty()) local_endpoint_id_.clear(); } -template -bool ClientProxy::isAdvertising() { - Synchronized s(lock_.get()); +bool ClientProxy::IsAdvertising() const { + MutexLock lock(&mutex_); - return !advertising_info_.isNull(); + return !advertising_info_.IsEmpty(); } -template -std::string ClientProxy::getAdvertisingServiceId() { - Synchronized s(lock_.get()); - - if (!isAdvertising()) { - return ""; - } - - return advertising_info_->service_id; +std::string ClientProxy::GetAdvertisingServiceId() const { + MutexLock lock(&mutex_); + return advertising_info_.service_id; } -template -void ClientProxy::startedDiscovery( - const std::string& service_id, const Strategy& strategy, - Ptr discovery_listener, - const std::vector& mediums) { - Synchronized s(lock_.get()); - - discovery_info_.destroy(); - discovery_info_ = MakePtr(new DiscoveryInfo(service_id, discovery_listener)); +std::string ClientProxy::GetServiceId() const { + MutexLock lock(&mutex_); + if (IsAdvertising()) + return advertising_info_.service_id; + if (IsDiscovering()) + return discovery_info_.service_id; + return "idle_service_id"; } -template -void ClientProxy::stoppedDiscovery() { - Synchronized s(lock_.get()); +void ClientProxy::StartedDiscovery( + const std::string& service_id, Strategy strategy, + const DiscoveryListener& listener, + absl::Span mediums) { + MutexLock lock(&mutex_); - if (isDiscovering()) { + if (connections_.empty()) local_endpoint_id_.clear(); + discovery_info_ = DiscoveryInfo{service_id, listener}; +} + +void ClientProxy::StoppedDiscovery() { + MutexLock lock(&mutex_); + + if (IsDiscovering()) { discovered_endpoint_ids_.clear(); - discovery_info_.destroy(); + discovery_info_.Clear(); } + if (connections_.empty()) local_endpoint_id_.clear(); } -template -bool ClientProxy::isDiscoveringServiceId( - const std::string& service_id) { - Synchronized s(lock_.get()); +bool ClientProxy::IsDiscoveringServiceId(const std::string& service_id) const { + MutexLock lock(&mutex_); - return isDiscovering() && service_id == discovery_info_->service_id; + return IsDiscovering() && service_id == discovery_info_.service_id; } -template -bool ClientProxy::isDiscovering() { - Synchronized s(lock_.get()); +bool ClientProxy::IsDiscovering() const { + MutexLock lock(&mutex_); - return !discovery_info_.isNull(); + return !discovery_info_.IsEmpty(); } -template -std::string ClientProxy::getDiscoveryServiceId() { - Synchronized s(lock_.get()); +std::string ClientProxy::GetDiscoveryServiceId() const { + MutexLock lock(&mutex_); - if (!isDiscovering()) { - return ""; + return discovery_info_.service_id; +} + +void ClientProxy::OnEndpointFound(const std::string& service_id, + const std::string& endpoint_id, + const ByteArray& endpoint_info, + proto::connections::Medium medium) { + MutexLock lock(&mutex_); + + NEARBY_LOG(INFO, + "ClientProxy [Endpoint Found]: [enter] id=%s; service=%s; info=%s", + endpoint_id.c_str(), service_id.c_str(), + absl::BytesToHexString(endpoint_info.data()).c_str()); + if (!IsDiscoveringServiceId(service_id)) { + NEARBY_LOG(INFO, "ClientProxy [Endpoint Found]: [no discovery] id=%s", + endpoint_id.c_str()); + return; } - - return discovery_info_->service_id; -} - -template -void ClientProxy::onEndpointFound(const std::string& endpoint_id, - const std::string& service_id, - const std::string& endpoint_name, - proto::connections::Medium medium) { - Synchronized s(lock_.get()); - - if (isDiscoveringServiceId(service_id)) { - if (discovered_endpoint_ids_.find(endpoint_id) != - discovered_endpoint_ids_.end()) { - // TODO(tracyzhou): Add logging. - return; - } - discovered_endpoint_ids_.insert(endpoint_id); - discovery_info_->discovery_listener->onEndpointFound(MakeConstPtr( - new OnEndpointFoundParams(endpoint_id, service_id, endpoint_name))); + if (discovered_endpoint_ids_.count(endpoint_id)) { + NEARBY_LOG(INFO, "ClientProxy [Endpoint Found]: [duplicate] id=%s", + endpoint_id.c_str()); + return; } + discovered_endpoint_ids_.insert(endpoint_id); + discovery_info_.listener.endpoint_found_cb(endpoint_id, endpoint_info, + service_id); } -template -void ClientProxy::onEndpointLost(const std::string& service_id, - const std::string& endpoint_id) { - Synchronized s(lock_.get()); +void ClientProxy::OnEndpointLost(const std::string& service_id, + const std::string& endpoint_id) { + MutexLock lock(&mutex_); - if (isDiscoveringServiceId(service_id)) { - std::set::const_iterator it = - discovered_endpoint_ids_.find(endpoint_id); - if (it == discovered_endpoint_ids_.end()) { - return; - } - discovered_endpoint_ids_.erase(it); - discovery_info_->discovery_listener->onEndpointLost( - MakeConstPtr(new OnEndpointLostParams(endpoint_id))); - } + if (!IsDiscoveringServiceId(service_id)) return; + const auto it = discovered_endpoint_ids_.find(endpoint_id); + if (it == discovered_endpoint_ids_.end()) return; + discovered_endpoint_ids_.erase(it); + discovery_info_.listener.endpoint_lost_cb(endpoint_id); } -template -void ClientProxy::onConnectionInitiated( - const std::string& endpoint_id, const std::string& endpoint_name, - const std::string& authentication_token, - ConstPtr raw_authentication_token, bool is_incoming_connection, - Ptr connection_lifecycle_listener) { - Synchronized s(lock_.get()); - - ScopedPtr> scoped_raw_authentication_token( - raw_authentication_token); +void ClientProxy::OnConnectionInitiated(const std::string& endpoint_id, + const ConnectionResponseInfo& info, + const ConnectionOptions& options, + const ConnectionListener& listener) { + MutexLock lock(&mutex_); // Whether this is incoming or outgoing, the local and remote endpoints both // still need to accept this connection, so set its establishment status to // PENDING. - connection_establishment_statuses_.insert( - std::make_pair(endpoint_id, ConnectionMetadata(is_incoming_connection))); - - // Remember the ConnectionLifecycleListener for this endpoint. - connection_lifecycle_listeners_.insert( - std::make_pair(endpoint_id, connection_lifecycle_listener)); - + auto result = connections_.emplace( + endpoint_id, Connection{ + .is_incoming = info.is_incoming_connection, + .connection_listener = listener, + .connection_options = options, + }); + // Instead of using structured binding which is nice, but banned + // (can not use c++17 features, until chromium does) we unpack manually. + auto& pair_iter = result.first; + bool inserted = result.second; + NEARBY_LOG(INFO, + "ClientProxy [Connection Initiated]: add Connection: client=%p, " + "id=%s; inserted=%d", + this, endpoint_id.c_str(), inserted); + DCHECK(inserted); + const Connection& item = pair_iter->second; // Notify the client. // // Note: we allow devices to connect to an advertiser even after it stops - // advertising, so no need to check isAdvertising() here. - connection_lifecycle_listeners_.find(endpoint_id) - ->second->onConnectionInitiated( - MakeConstPtr(new OnConnectionInitiatedParams( - endpoint_id, endpoint_name, authentication_token, - scoped_raw_authentication_token.release(), - is_incoming_connection))); + // advertising, so no need to check IsAdvertising() here. + item.connection_listener.initiated_cb(endpoint_id, info); } -template -void ClientProxy::onConnectionResult(const std::string& endpoint_id, - Status::Value status) { - Synchronized s(lock_.get()); +void ClientProxy::OnConnectionAccepted(const std::string& endpoint_id) { + MutexLock lock(&mutex_); - if (!hasPendingConnectionToEndpoint(endpoint_id)) { - // TODO(tracyzhou): Add logging. + if (!HasPendingConnectionToEndpoint(endpoint_id)) { + NEARBY_LOG( + INFO, "ClientProxy [Connection Accepted]: no pending connection; id=%s", + endpoint_id.c_str()); return; } // Notify the client. - connection_lifecycle_listeners_.find(endpoint_id) - ->second->onConnectionResult( - MakeConstPtr(new OnConnectionResultParams(endpoint_id, status))); - if (Status::SUCCESS == status) { - // Mark ourselves as connected. Payloads should now be allowed. - typename ConnectionEstablishmentStatusesMap::iterator it = - connection_establishment_statuses_.find(endpoint_id); - if (it != connection_establishment_statuses_.end()) { - it->second.status = ConnectionEstablishmentStatus::CONNECTED; - } - } else { - // Otherwise, clean up. - onDisconnected(endpoint_id, false /* notify */); + Connection* item = LookupConnection(endpoint_id); + if (item != nullptr) { + item->connection_listener.accepted_cb(endpoint_id); + item->status = Connection::kConnected; } } -template -void ClientProxy::onBandwidthChanged(const std::string& endpoint_id, - std::int32_t quality) { - Synchronized s(lock_.get()); +void ClientProxy::OnConnectionRejected(const std::string& endpoint_id, + const Status& status) { + MutexLock lock(&mutex_); - ConnectionLifecycleListenersMap::iterator it = - connection_lifecycle_listeners_.find(endpoint_id); - if (it != connection_lifecycle_listeners_.end()) { - it->second->onBandwidthChanged( - MakeConstPtr(new OnBandwidthChangedParams(endpoint_id, quality))); + if (!HasPendingConnectionToEndpoint(endpoint_id)) { + NEARBY_LOG( + INFO, "ClientProxy [Connection Rejected]: no pending connection; id=%s", + endpoint_id.c_str()); + return; + } + + // Notify the client. + const Connection* item = LookupConnection(endpoint_id); + if (item != nullptr) { + item->connection_listener.rejected_cb(endpoint_id, status); + OnDisconnected(endpoint_id, false /* notify */); } } -template -void ClientProxy::onDisconnected(const std::string& endpoint_id, - bool notify) { - Synchronized s(lock_.get()); +void ClientProxy::OnBandwidthChanged(const std::string& endpoint_id, + Medium new_medium) { + MutexLock lock(&mutex_); - connection_establishment_statuses_.erase(endpoint_id); + const Connection* item = LookupConnection(endpoint_id); + if (item != nullptr) { + item->connection_listener.bandwidth_changed_cb(endpoint_id, new_medium); + } +} - client_proxy::eraseOwnedPtrFromMap(payload_listeners_, endpoint_id); +void ClientProxy::OnDisconnected(const std::string& endpoint_id, bool notify) { + MutexLock lock(&mutex_); - ConnectionLifecycleListenersMap::iterator it = - connection_lifecycle_listeners_.find(endpoint_id); - if (it != connection_lifecycle_listeners_.end()) { + const Connection* item = LookupConnection(endpoint_id); + if (item != nullptr) { if (notify) { - it->second->onDisconnected( - MakeConstPtr(new OnDisconnectedParams(endpoint_id))); + item->connection_listener.disconnected_cb({endpoint_id}); } - it->second.destroy(); - connection_lifecycle_listeners_.erase(it); + connections_.erase(endpoint_id); + if (connections_.empty()) local_endpoint_id_.clear(); } } -template -bool ClientProxy::isConnectedToEndpoint( - const std::string& endpoint_id) { - Synchronized s(lock_.get()); +bool ClientProxy::ConnectionStatusMatches(const std::string& endpoint_id, + Connection::Status status) const { + MutexLock lock(&mutex_); - typename ConnectionEstablishmentStatusesMap::iterator it = - connection_establishment_statuses_.find(endpoint_id); - if (it == connection_establishment_statuses_.end()) { - return false; + const Connection* item = LookupConnection(endpoint_id); + if (item != nullptr) { + return item->status == status; } - const ConnectionMetadata& metadata = it->second; - return metadata.status == ConnectionEstablishmentStatus::CONNECTED; + return false; } -template -std::vector ClientProxy::getConnectedEndpoints() { - Synchronized s(lock_.get()); +BooleanMediumSelector ClientProxy::GetUpgradeMediums( + const std::string& endpoint_id) const { + MutexLock lock(&mutex_); + + const Connection* item = LookupConnection(endpoint_id); + if (item != nullptr) { + return item->connection_options.allowed; + } + return {}; +} + +bool ClientProxy::IsConnectedToEndpoint(const std::string& endpoint_id) const { + return ConnectionStatusMatches(endpoint_id, Connection::kConnected); +} + +std::vector ClientProxy::GetMatchingEndpoints( + std::function pred) const { + MutexLock lock(&mutex_); std::vector connected_endpoints; - for (typename ConnectionEstablishmentStatusesMap::iterator it = - connection_establishment_statuses_.begin(); - it != connection_establishment_statuses_.end(); it++) { - const std::string& endpoint_id = it->first; - const ConnectionMetadata& metadata = it->second; - if (ConnectionEstablishmentStatus::CONNECTED == metadata.status) { + for (const auto& pair : connections_) { + const auto& endpoint_id = pair.first; + const auto& connection = pair.second; + if (pred(connection)) { connected_endpoints.push_back(endpoint_id); } } return connected_endpoints; } -template -std::vector ClientProxy::getPendingConnectedEndpoints() { - Synchronized s(lock_.get()); +std::vector ClientProxy::GetPendingConnectedEndpoints() const { + return GetMatchingEndpoints([](const Connection& connection) { + return connection.status != Connection::kConnected; + }); +} - std::vector pending_connected_endpoints; +std::vector ClientProxy::GetConnectedEndpoints() const { + return GetMatchingEndpoints([](const Connection& connection) { + return connection.status == Connection::kConnected; + }); +} - for (typename ConnectionEstablishmentStatusesMap::iterator it = - connection_establishment_statuses_.begin(); - it != connection_establishment_statuses_.end(); it++) { - const std::string& endpoint_id = it->first; - const ConnectionMetadata& metadata = it->second; - if (ConnectionEstablishmentStatus::CONNECTED != metadata.status) { - pending_connected_endpoints.push_back(endpoint_id); +std::int32_t ClientProxy::GetNumOutgoingConnections() const { + return GetMatchingEndpoints([](const Connection& connection) { + return connection.status == Connection::kConnected && + !connection.is_incoming; + }) + .size(); +} + +std::int32_t ClientProxy::GetNumIncomingConnections() const { + return GetMatchingEndpoints([](const Connection& connection) { + return connection.status == Connection::kConnected && + connection.is_incoming; + }) + .size(); +} + +bool ClientProxy::HasPendingConnectionToEndpoint( + const std::string& endpoint_id) const { + MutexLock lock(&mutex_); + + const Connection* item = LookupConnection(endpoint_id); + if (item != nullptr) { + return item->status != Connection::kConnected; + } + return false; +} + +bool ClientProxy::HasLocalEndpointResponded( + const std::string& endpoint_id) const { + MutexLock lock(&mutex_); + + return ConnectionStatusesContains( + endpoint_id, + static_cast(Connection::kLocalEndpointAccepted | + Connection::kLocalEndpointRejected)); +} + +bool ClientProxy::HasRemoteEndpointResponded( + const std::string& endpoint_id) const { + MutexLock lock(&mutex_); + + return ConnectionStatusesContains( + endpoint_id, + static_cast(Connection::kRemoteEndpointAccepted | + Connection::kRemoteEndpointRejected)); +} + +void ClientProxy::LocalEndpointAcceptedConnection( + const std::string& endpoint_id, const PayloadListener& listener) { + MutexLock lock(&mutex_); + + if (HasLocalEndpointResponded(endpoint_id)) { + NEARBY_LOG( + INFO, + "ClientProxy [Local Accepted]: local endpoint has responded; id=%s", + endpoint_id.c_str()); + return; + } + + AppendConnectionStatus(endpoint_id, Connection::kLocalEndpointAccepted); + Connection* item = LookupConnection(endpoint_id); + if (item != nullptr) { + item->payload_listener = listener; + } +} + +void ClientProxy::LocalEndpointRejectedConnection( + const std::string& endpoint_id) { + MutexLock lock(&mutex_); + + if (HasLocalEndpointResponded(endpoint_id)) { + NEARBY_LOG( + INFO, + "ClientProxy [Local Rejected]: local endpoint has responded; id=%s", + endpoint_id.c_str()); + return; + } + + AppendConnectionStatus(endpoint_id, Connection::kLocalEndpointRejected); +} + +void ClientProxy::RemoteEndpointAcceptedConnection( + const std::string& endpoint_id) { + MutexLock lock(&mutex_); + + if (HasRemoteEndpointResponded(endpoint_id)) { + NEARBY_LOG( + INFO, + "ClientProxy [Remote Accepted]: remote endpoint has responded; id=%s", + endpoint_id.c_str()); + return; + } + + AppendConnectionStatus(endpoint_id, Connection::kRemoteEndpointAccepted); +} + +void ClientProxy::RemoteEndpointRejectedConnection( + const std::string& endpoint_id) { + MutexLock lock(&mutex_); + + if (HasRemoteEndpointResponded(endpoint_id)) { + NEARBY_LOG( + INFO, + "ClientProxy [Remote Rejected]: remote endpoint has responded; id=%s", + endpoint_id.c_str()); + return; + } + + AppendConnectionStatus(endpoint_id, Connection::kRemoteEndpointRejected); +} + +bool ClientProxy::IsConnectionAccepted(const std::string& endpoint_id) const { + MutexLock lock(&mutex_); + + return ConnectionStatusesContains(endpoint_id, + Connection::kLocalEndpointAccepted) && + ConnectionStatusesContains(endpoint_id, + Connection::kRemoteEndpointAccepted); +} + +bool ClientProxy::IsConnectionRejected(const std::string& endpoint_id) const { + MutexLock lock(&mutex_); + + return ConnectionStatusesContains( + endpoint_id, + static_cast(Connection::kLocalEndpointRejected | + Connection::kRemoteEndpointRejected)); +} + +bool ClientProxy::LocalConnectionIsAccepted(std::string endpoint_id) const { + return ConnectionStatusesContains( + endpoint_id, ClientProxy::Connection::kLocalEndpointAccepted); +} + +bool ClientProxy::RemoteConnectionIsAccepted(std::string endpoint_id) const { + return ConnectionStatusesContains( + endpoint_id, ClientProxy::Connection::kRemoteEndpointAccepted); +} + +void ClientProxy::OnPayload(const std::string& endpoint_id, Payload payload) { + MutexLock lock(&mutex_); + + if (IsConnectedToEndpoint(endpoint_id)) { + const Connection* item = LookupConnection(endpoint_id); + if (item != nullptr) { + item->payload_listener.payload_cb(endpoint_id, std::move(payload)); } } - return pending_connected_endpoints; } -template -std::int32_t ClientProxy::getNumOutgoingConnections() { - Synchronized s(lock_.get()); +const ClientProxy::Connection* ClientProxy::LookupConnection( + const std::string& endpoint_id) const { + auto item = connections_.find(endpoint_id); + return item != connections_.end() ? &item->second : nullptr; +} - std::int32_t num_outgoing_connections = 0; +ClientProxy::Connection* ClientProxy::LookupConnection( + const std::string& endpoint_id) { + auto item = connections_.find(endpoint_id); + return item != connections_.end() ? &item->second : nullptr; +} - for (typename ConnectionEstablishmentStatusesMap::iterator it = - connection_establishment_statuses_.begin(); - it != connection_establishment_statuses_.end(); it++) { - const ConnectionMetadata& metadata = it->second; - if (ConnectionEstablishmentStatus::CONNECTED == metadata.status && - !metadata.is_incoming) { - num_outgoing_connections++; +void ClientProxy::OnPayloadProgress(const std::string& endpoint_id, + const PayloadProgressInfo& info) { + MutexLock lock(&mutex_); + + if (IsConnectedToEndpoint(endpoint_id)) { + Connection* item = LookupConnection(endpoint_id); + if (item != nullptr) { + item->payload_listener.payload_progress_cb(endpoint_id, info); } } - return num_outgoing_connections; } -template -std::int32_t ClientProxy::getNumIncomingConnections() { - Synchronized s(lock_.get()); - - std::int32_t num_incoming_connections = 0; - - for (typename ConnectionEstablishmentStatusesMap::iterator it = - connection_establishment_statuses_.begin(); - it != connection_establishment_statuses_.end(); it++) { - const ConnectionMetadata& metadata = it->second; - if (ConnectionEstablishmentStatus::CONNECTED == metadata.status && - metadata.is_incoming) { - num_incoming_connections++; - } - } - return num_incoming_connections; +bool operator==(const ClientProxy& lhs, const ClientProxy& rhs) { + return lhs.GetClientId() == rhs.GetClientId(); } -template -bool ClientProxy::hasPendingConnectionToEndpoint( - const std::string& endpoint_id) { - Synchronized s(lock_.get()); - - typename ConnectionEstablishmentStatusesMap::iterator it = - connection_establishment_statuses_.find(endpoint_id); - if (it == connection_establishment_statuses_.end()) { - return false; - } - const ConnectionMetadata& metadata = it->second; - return metadata.status != ConnectionEstablishmentStatus::CONNECTED; +bool operator<(const ClientProxy& lhs, const ClientProxy& rhs) { + return lhs.GetClientId() < rhs.GetClientId(); } -template -bool ClientProxy::hasLocalEndpointResponded( - const std::string& endpoint_id) { - Synchronized s(lock_.get()); - - return connectionEstablishmentStatusesContains( - endpoint_id, - ConnectionEstablishmentStatus::LOCAL_ENDPOINT_ACCEPTED) || - connectionEstablishmentStatusesContains( - endpoint_id, - ConnectionEstablishmentStatus::LOCAL_ENDPOINT_REJECTED); -} - -template -bool ClientProxy::hasRemoteEndpointResponded( - const std::string& endpoint_id) { - Synchronized s(lock_.get()); - - return connectionEstablishmentStatusesContains( - endpoint_id, - ConnectionEstablishmentStatus::REMOTE_ENDPOINT_ACCEPTED) || - connectionEstablishmentStatusesContains( - endpoint_id, - ConnectionEstablishmentStatus::REMOTE_ENDPOINT_REJECTED); -} - -template -void ClientProxy::localEndpointAcceptedConnection( - const std::string& endpoint_id, Ptr payload_listener) { - Synchronized s(lock_.get()); - - if (hasLocalEndpointResponded(endpoint_id)) { - // TODO(tracyzhou): Add logging. - return; - } - - appendConnectionEstablishmentStatus( - endpoint_id, ConnectionEstablishmentStatus::LOCAL_ENDPOINT_ACCEPTED); - payload_listeners_.insert(std::make_pair(endpoint_id, payload_listener)); -} - -template -void ClientProxy::localEndpointRejectedConnection( - const std::string& endpoint_id) { - Synchronized s(lock_.get()); - - if (hasLocalEndpointResponded(endpoint_id)) { - // TODO(tracyzhou): Add logging. - return; - } - - appendConnectionEstablishmentStatus( - endpoint_id, ConnectionEstablishmentStatus::LOCAL_ENDPOINT_REJECTED); -} - -template -void ClientProxy::remoteEndpointAcceptedConnection( - const std::string& endpoint_id) { - Synchronized s(lock_.get()); - - if (hasRemoteEndpointResponded(endpoint_id)) { - // TODO(tracyzhou): Add logging. - return; - } - - appendConnectionEstablishmentStatus( - endpoint_id, ConnectionEstablishmentStatus::REMOTE_ENDPOINT_ACCEPTED); -} - -template -void ClientProxy::remoteEndpointRejectedConnection( - const std::string& endpoint_id) { - Synchronized s(lock_.get()); - - if (hasRemoteEndpointResponded(endpoint_id)) { - // TODO(tracyzhou): Add logging. - return; - } - - appendConnectionEstablishmentStatus( - endpoint_id, ConnectionEstablishmentStatus::REMOTE_ENDPOINT_REJECTED); -} - -template -bool ClientProxy::isConnectionAccepted( - const std::string& endpoint_id) { - Synchronized s(lock_.get()); - - return connectionEstablishmentStatusesContains( - endpoint_id, - ConnectionEstablishmentStatus::LOCAL_ENDPOINT_ACCEPTED) && - connectionEstablishmentStatusesContains( - endpoint_id, - ConnectionEstablishmentStatus::REMOTE_ENDPOINT_ACCEPTED); -} - -template -bool ClientProxy::isConnectionRejected( - const std::string& endpoint_id) { - Synchronized s(lock_.get()); - - return connectionEstablishmentStatusesContains( - endpoint_id, - ConnectionEstablishmentStatus::LOCAL_ENDPOINT_REJECTED) || - connectionEstablishmentStatusesContains( - endpoint_id, - ConnectionEstablishmentStatus::REMOTE_ENDPOINT_REJECTED); -} - -template -void ClientProxy::onPayloadReceived(const std::string& endpoint_id, - ConstPtr payload) { - Synchronized s(lock_.get()); - - // Avoid leaks. - ScopedPtr> scoped_payload(payload); - - if (isConnectedToEndpoint(endpoint_id)) { - payload_listeners_.find(endpoint_id) - ->second->onPayloadReceived(MakeConstPtr(new OnPayloadReceivedParams( - endpoint_id, scoped_payload.release()))); - } -} - -template -void ClientProxy::onPayloadTransferUpdate( - const std::string& endpoint_id, - const PayloadTransferUpdate& payload_transfer_update) { - Synchronized s(lock_.get()); - - if (isConnectedToEndpoint(endpoint_id)) { - payload_listeners_.find(endpoint_id) - ->second->onPayloadTransferUpdate( - MakeConstPtr(new OnPayloadTransferUpdateParams( - endpoint_id, payload_transfer_update))); - } -} - -template -bool ClientProxy::operator==(const ClientProxy& rhs) { - return this->getClientId() == rhs.getClientId(); -} - -template -bool ClientProxy::operator<(const ClientProxy& rhs) { - return this->getClientId() < rhs.getClientId(); -} - -template -void ClientProxy::removeAllEndpoints() { - Synchronized s(lock_.get()); +void ClientProxy::RemoveAllEndpoints() { + MutexLock lock(&mutex_); // Note: we may want to notify the client of onDisconnected() for each // endpoint, in the case when this is called from stopAllEndpoints(). For now, // just remove without notifying. - for (ConnectionLifecycleListenersMap::iterator it = - connection_lifecycle_listeners_.begin(); - it != connection_lifecycle_listeners_.end(); it++) { - it->second.destroy(); - } - connection_lifecycle_listeners_.clear(); - - for (PayloadListenersMap::iterator it = payload_listeners_.begin(); - it != payload_listeners_.end(); it++) { - it->second.destroy(); - } - payload_listeners_.clear(); - - connection_establishment_statuses_.clear(); + connections_.clear(); + local_endpoint_id_.clear(); } -template -bool ClientProxy::connectionEstablishmentStatusesContains( - const std::string& endpoint_id, - typename ConnectionEstablishmentStatus::Value status_to_match) { - typename ConnectionEstablishmentStatusesMap::iterator it = - connection_establishment_statuses_.find(endpoint_id); - if (it == connection_establishment_statuses_.end()) { - return false; +bool ClientProxy::ConnectionStatusesContains( + const std::string& endpoint_id, Connection::Status status_to_match) const { + const Connection* item = LookupConnection(endpoint_id); + if (item != nullptr) { + return (item->status & status_to_match) != 0; } - const ConnectionMetadata& metadata = it->second; - return (metadata.status & status_to_match) != 0; + return false; } -template -void ClientProxy::appendConnectionEstablishmentStatus( - const std::string& endpoint_id, - typename ConnectionEstablishmentStatus::Value status_to_append) { - typename ConnectionEstablishmentStatusesMap::iterator it = - connection_establishment_statuses_.find(endpoint_id); - if (it == connection_establishment_statuses_.end()) { - return; +void ClientProxy::AppendConnectionStatus(const std::string& endpoint_id, + Connection::Status status_to_append) { + Connection* item = LookupConnection(endpoint_id); + if (item != nullptr) { + item->status = + static_cast(item->status | status_to_append); } - ConnectionMetadata& metadata = it->second; - metadata.status = static_cast( - metadata.status | status_to_append); } } // namespace connections diff --git a/cpp/core/internal/client_proxy.h b/cpp/core/internal/client_proxy.h index 98e76fbb..6bc8ebc5 100644 --- a/cpp/core/internal/client_proxy.h +++ b/cpp/core/internal/client_proxy.h @@ -2,240 +2,227 @@ #define CORE_INTERNAL_CLIENT_PROXY_H_ #include -#include -#include +#include #include #include "core/listeners.h" +#include "core/options.h" +#include "core/status.h" #include "core/strategy.h" -#include "platform/api/lock.h" -#include "platform/byte_array.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "platform/base/byte_array.h" +#include "platform/base/prng.h" +#include "platform/public/mutex.h" #include "proto/connections_enums.pb.h" +// Prefer using absl:: versions of a set and a map; they tend to be more +// efficient: implementation is using open-addressing hash tables. +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" +#include "absl/types/span.h" namespace location { namespace nearby { namespace connections { -template -class ClientProxy { +// CLientProxy is tracking state of client's connection, and serves as +// a proxy for notifications sent to this client. +class ClientProxy final { public: - static const std::int32_t kEndpointIdLength; + static constexpr int kEndpointIdLength = 4; ClientProxy(); ~ClientProxy(); + ClientProxy(ClientProxy&&) = default; + ClientProxy& operator=(ClientProxy&&) = default; - std::int64_t getClientId() const; + std::int64_t GetClientId() const; - std::string generateLocalEndpointId(); + std::string GetLocalEndpointId(); // Clears all the runtime state of this client. - void reset(); + void Reset(); // Marks this client as advertising with the given callbacks. - void startedAdvertising( - const std::string& service_id, const Strategy& strategy, - Ptr connection_lifecycle_listener, - const std::vector& mediums); + void StartedAdvertising( + const std::string& service_id, Strategy strategy, + const ConnectionListener& connection_lifecycle_listener, + absl::Span mediums); // Marks this client as not advertising. - void stoppedAdvertising(); - bool isAdvertising(); - std::string getAdvertisingServiceId(); + void StoppedAdvertising(); + bool IsAdvertising() const; + std::string GetAdvertisingServiceId() const; + + // Get service ID of a surrently active link (either advertising, or + // discovering). + std::string GetServiceId() const; // Marks this client as discovering with the given callback. - void startedDiscovery(const std::string& service_id, const Strategy& strategy, - Ptr discovery_listener, - const std::vector& mediums); + void StartedDiscovery(const std::string& service_id, Strategy strategy, + const DiscoveryListener& discovery_listener, + absl::Span mediums); // Marks this client as not discovering at all. - void stoppedDiscovery(); - bool isDiscoveringServiceId(const std::string& service_id); - bool isDiscovering(); - std::string getDiscoveryServiceId(); + void StoppedDiscovery(); + bool IsDiscoveringServiceId(const std::string& service_id) const; + bool IsDiscovering() const; + std::string GetDiscoveryServiceId() const; - // Proxies to the client's DiscoveryListener.onEndpointFound() callback. - void onEndpointFound(const std::string& endpoint_id, - const std::string& service_id, - const std::string& endpoint_name, + // Proxies to the client's DiscoveryListener::OnEndpointFound() callback. + void OnEndpointFound(const std::string& service_id, + const std::string& endpoint_id, + const ByteArray& endpoint_info, proto::connections::Medium medium); - // Proxies to the client's DiscoveryListener.onEndpointLost() callback. - void onEndpointLost(const std::string& service_id, + // Proxies to the client's DiscoveryListener::OnEndpointLost() callback. + void OnEndpointLost(const std::string& service_id, const std::string& endpoint_id); - // Proxies to the client's ConnectionLifecycleListener.onConnectionInitiated() - // callback. - void onConnectionInitiated( - const std::string& endpoint_id, const std::string& endpoint_name, - const std::string& authentication_token, - ConstPtr raw_authentication_token, bool is_incoming_connection, - Ptr connection_lifecycle_listener); - // Proxies to the client's ConnectionLifecycleListener.onConnectionResult() - // callback. - void onConnectionResult(const std::string& endpoint_id, Status::Value status); + // Proxies to the client's ConnectionListener::OnInitiated() callback. + void OnConnectionInitiated(const std::string& endpoint_id, + const ConnectionResponseInfo& info, + const ConnectionOptions& options, + const ConnectionListener& listener); - void onBandwidthChanged(const std::string& endpoint_id, std::int32_t quality); + // Proxies to the client's ConnectionListener::OnAccepted() callback. + void OnConnectionAccepted(const std::string& endpoint_id); + // Proxies to the client's ConnectionListener::OnRejected() callback. + void OnConnectionRejected(const std::string& endpoint_id, + const Status& status); + + void OnBandwidthChanged(const std::string& endpoint_id, Medium new_medium); // Removes the endpoint from this client's list of connected endpoints. If // notify is true, also calls the client's - // ConnectionLifecycleListener.onDisconnected() callback. - void onDisconnected(const std::string& endpoint_id, bool notify); + // ConnectionListener.disconnected_cb() callback. + void OnDisconnected(const std::string& endpoint_id, bool notify); + // Returns all mediums eligible for upgrade. + BooleanMediumSelector GetUpgradeMediums(const std::string& endpoint_id) const; // Returns true if it's safe to send payloads to this endpoint. - bool isConnectedToEndpoint(const std::string& endpoint_id); + bool IsConnectedToEndpoint(const std::string& endpoint_id) const; // Returns all endpoints that can safely be sent payloads. - std::vector getConnectedEndpoints(); + std::vector GetConnectedEndpoints() const; // Returns all endpoints that are still awaiting acceptance. - std::vector getPendingConnectedEndpoints(); + std::vector GetPendingConnectedEndpoints() const; // Returns the number of endpoints that are connected and outgoing. - std::int32_t getNumOutgoingConnections(); + std::int32_t GetNumOutgoingConnections() const; // Returns the number of endpoints that are connected and incoming. - std::int32_t getNumIncomingConnections(); + std::int32_t GetNumIncomingConnections() const; // If true, then we're in the process of approving (or rejecting) a // connection. No payloads should be sent until isConnectedToEndpoint() // returns true. - bool hasPendingConnectionToEndpoint(const std::string& endpoint_id); + bool HasPendingConnectionToEndpoint(const std::string& endpoint_id) const; // Returns true if the local endpoint has already marked itself as // accepted/rejected. - bool hasLocalEndpointResponded(const std::string& endpoint_id); + bool HasLocalEndpointResponded(const std::string& endpoint_id) const; // Returns true if the remote endpoint has already marked themselves as // accepted/rejected. - bool hasRemoteEndpointResponded(const std::string& endpoint_id); + bool HasRemoteEndpointResponded(const std::string& endpoint_id) const; // Marks the local endpoint as having accepted the connection. - void localEndpointAcceptedConnection(const std::string& endpoint_id, - Ptr payload_listener); + void LocalEndpointAcceptedConnection(const std::string& endpoint_id, + const PayloadListener& listener); // Marks the local endpoint as having rejected the connection. - void localEndpointRejectedConnection(const std::string& endpoint_id); + void LocalEndpointRejectedConnection(const std::string& endpoint_id); // Marks the remote endpoint as having accepted the connection. - void remoteEndpointAcceptedConnection(const std::string& endpoint_id); + void RemoteEndpointAcceptedConnection(const std::string& endpoint_id); // Marks the remote endpoint as having rejected the connection. - void remoteEndpointRejectedConnection(const std::string& endpoint_id); + void RemoteEndpointRejectedConnection(const std::string& endpoint_id); // Returns true if both the local endpoint and the remote endpoint have // accepted the connection. - bool isConnectionAccepted(const std::string& endpoint_id); + bool IsConnectionAccepted(const std::string& endpoint_id) const; // Returns true if either the local endpoint or the remote endpoint has // rejected the connection. - bool isConnectionRejected(const std::string& endpoint_id); + bool IsConnectionRejected(const std::string& endpoint_id) const; - // Proxies to the client's PayloadListener.onPayloadReceived() callback. - void onPayloadReceived(const std::string& endpoint_id, - ConstPtr payload); - // Proxies to the client's PayloadListener.onPayloadTransferUpdate() callback. - void onPayloadTransferUpdate( - const std::string& endpoint_id, - const PayloadTransferUpdate& payload_transfer_update); - - // Operator overloads when comparing Ptr. - bool operator==(const ClientProxy& rhs); - bool operator<(const ClientProxy& rhs); + // Proxies to the client's PayloadListener::OnPayload() callback. + void OnPayload(const std::string& endpoint_id, Payload payload); + // Proxies to the client's PayloadListener::OnPayloadProgress() callback. + void OnPayloadProgress(const std::string& endpoint_id, + const PayloadProgressInfo& info); + bool LocalConnectionIsAccepted(std::string endpoint_id) const; + bool RemoteConnectionIsAccepted(std::string endpoint_id) const; private: - struct ConnectionEstablishmentStatus { - enum Value { - PENDING = 0, - LOCAL_ENDPOINT_ACCEPTED = 1 << 0, - LOCAL_ENDPOINT_REJECTED = 1 << 1, - REMOTE_ENDPOINT_ACCEPTED = 1 << 2, - REMOTE_ENDPOINT_REJECTED = 1 << 3, - CONNECTED = 1 << 4, + struct Connection { + // Status: may be either: + // Connection::PENDING, or combination of + // Connection::LOCAL_ENDPOINT_ACCEPTED: + // Connection::LOCAL_ENDPOINT_REJECTED and + // Connection::REMOTE_ENDPOINT_ACCEPTED: + // Connection::REMOTE_ENDPOINT_REJECTED, or + // Connection::CONNECTED. + // Only when this is set to CONNECTED should you allow payload transfers. + // + // We want this enum to be implicitly convertible to int, because + // we perform bit operations on it. + enum Status : uint8_t { + kPending = 0, + kLocalEndpointAccepted = 1 << 0, + kLocalEndpointRejected = 1 << 1, + kRemoteEndpointAccepted = 1 << 2, + kRemoteEndpointRejected = 1 << 3, + kConnected = 1 << 4, }; + bool is_incoming{false}; + Status status{kPending}; + ConnectionListener connection_listener; + PayloadListener payload_listener; + ConnectionOptions connection_options; }; struct AdvertisingInfo { - const std::string service_id; - Ptr connection_lifecycle_listener; - - AdvertisingInfo( - const std::string& service_id, - Ptr connection_lifecycle_listener) - : service_id(service_id), - connection_lifecycle_listener(connection_lifecycle_listener) {} + std::string service_id; + ConnectionListener listener; + void Clear() { service_id.clear(); } + bool IsEmpty() const { return service_id.empty(); } }; struct DiscoveryInfo { - const std::string service_id; - ScopedPtr > discovery_listener; - - DiscoveryInfo(const std::string& service_id, - Ptr discovery_listener) - : service_id(service_id), discovery_listener(discovery_listener) {} + std::string service_id; + DiscoveryListener listener; + void Clear() { service_id.clear(); } + bool IsEmpty() const { return service_id.empty(); } }; - struct ConnectionMetadata { - const bool is_incoming; - typename ConnectionEstablishmentStatus::Value status; + void RemoveAllEndpoints(); + bool ConnectionStatusesContains(const std::string& endpoint_id, + Connection::Status status_to_match) const; + void AppendConnectionStatus(const std::string& endpoint_id, + Connection::Status status_to_append); - explicit ConnectionMetadata(bool is_incoming) - : is_incoming(is_incoming), - status(ConnectionEstablishmentStatus::PENDING) {} - }; + const Connection* LookupConnection(const std::string& endpoint_id) const; + Connection* LookupConnection(const std::string& endpoint_id); + bool ConnectionStatusMatches(const std::string& endpoint_id, + Connection::Status status) const; + std::vector GetMatchingEndpoints( + std::function pred) const; - void removeAllEndpoints(); + mutable RecursiveMutex mutex_; + std::int64_t client_id_; + std::string local_endpoint_id_; + Prng prng_; - bool connectionEstablishmentStatusesContains( - const std::string& endpoint_id, - typename ConnectionEstablishmentStatus::Value status_to_match); - void appendConnectionEstablishmentStatus( - const std::string& endpoint_id, - typename ConnectionEstablishmentStatus::Value status_to_append); + // If not empty, we are currently advertising and accepting connection + // requests for the given service_id. + AdvertisingInfo advertising_info_; - ScopedPtr > lock_; - const std::int64_t client_id_; + // If not empty, we are currently discovering for the given service_id. + DiscoveryInfo discovery_info_; - // If set, we are currently advertising and accepting connection requests for - // the given service_id. - Ptr advertising_info_; + // Maps endpoint_id to endpoint connection state. + absl::flat_hash_map connections_; - // If set, we are currently discovering for the given service_id. - Ptr discovery_info_; - - /** - * Map of endpoint_ids -> ConnectionMetadata. ConnectionMetadata.status may be - * either ConnectionEstablishmentStatus::PENDING, a combination of - * ConnectionEstablishmentStatus::LOCAL_ENDPOINT_ACCEPTED: - * ConnectionEstablishmentStatus::LOCAL_ENDPOINT_REJECTED and - * ConnectionEstablishmentStatus::REMOTE_ENDPOINT_ACCEPTED: - * ConnectionEstablishmentStatus::REMOTE_ENDPOINT_REJECTED, or - * ConnectionEstablishmentStatus::CONNECTED. Only when this is set to - * CONNECTED should you allow payload transfers. - */ - typedef std::map - ConnectionEstablishmentStatusesMap; - ConnectionEstablishmentStatusesMap connection_establishment_statuses_; - - /** - * Map of endpoint_ids -> ConnectionLifecycleListeners. Every endpoint in here - * is guaranteed to at least be in - * ConnectionEstablishmentStatus::PENDING -- the precise status can be found - * from the corresponding entry in connection_establishment_statuses. - */ - typedef std::map > - ConnectionLifecycleListenersMap; - ConnectionLifecycleListenersMap connection_lifecycle_listeners_; - - /** - * Map of endpoint_ids -> PayloadListeners. Every endpoint in here is - * guaranteed to at least be in - * ConnectionEstablishmentStatus::LOCAL_ENDPOINT_ACCEPTED -- the - * precise status can be found from the corresponding entry in - * connection_establishment_statuses. - */ - typedef std::map > PayloadListenersMap; - PayloadListenersMap payload_listeners_; - - /** - * A cache of endpoint ids that we've already notified the discoverer of. We - * check this cache before calling onEndpointFound() so that we don't notify - * the client multiple times for the same endpoint. This would otherwise - * happen because some mediums (like Bluetooth) repeatedly give us the same - * endpoints after each scan. - */ - std::set discovered_endpoint_ids_; + // A cache of endpoint ids that we've already notified the discoverer of. We + // check this cache before calling onEndpointFound() so that we don't notify + // the client multiple times for the same endpoint. This would otherwise + // happen because some mediums (like Bluetooth) repeatedly give us the same + // endpoints after each scan. + absl::flat_hash_set discovered_endpoint_ids_; }; +// Operator overloads when comparing Ptr. +bool operator==(const ClientProxy& lhs, const ClientProxy& rhs); +bool operator<(const ClientProxy& lhs, const ClientProxy& rhs); + } // namespace connections } // namespace nearby } // namespace location -#include "core/internal/client_proxy.cc" - #endif // CORE_INTERNAL_CLIENT_PROXY_H_ diff --git a/cpp/core_v2/internal/client_proxy_test.cc b/cpp/core/internal/client_proxy_test.cc similarity index 98% rename from cpp/core_v2/internal/client_proxy_test.cc rename to cpp/core/internal/client_proxy_test.cc index 94d22a67..2e7a92cd 100644 --- a/cpp/core_v2/internal/client_proxy_test.cc +++ b/cpp/core/internal/client_proxy_test.cc @@ -1,11 +1,11 @@ -#include "core_v2/internal/client_proxy.h" +#include "core/internal/client_proxy.h" #include -#include "core_v2/listeners.h" -#include "core_v2/options.h" -#include "core_v2/strategy.h" -#include "platform_v2/base/byte_array.h" +#include "core/listeners.h" +#include "core/options.h" +#include "core/strategy.h" +#include "platform/base/byte_array.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/container/flat_hash_set.h" diff --git a/cpp/core/internal/encryption_runner.cc b/cpp/core/internal/encryption_runner.cc index 9e463442..7d2e531d 100644 --- a/cpp/core/internal/encryption_runner.cc +++ b/cpp/core/internal/encryption_runner.cc @@ -2,324 +2,269 @@ #include #include +#include -#include "platform/base64_utils.h" -#include "platform/byte_array.h" -#include "platform/cancelable_alarm.h" -#include "platform/exception.h" -#include "platform/logging.h" +#include "platform/base/base64_utils.h" +#include "platform/base/byte_array.h" +#include "platform/base/exception.h" +#include "platform/public/cancelable_alarm.h" +#include "platform/public/logging.h" +#include "securegcm/ukey2_handshake.h" #include "absl/strings/ascii.h" - -namespace { - -std::int64_t kTimeoutMillis = 15 * 1000; // 15 seconds -std::int32_t kMaxUkey2VerificationStringLength = 32; -std::int32_t kTokenLength = 5; -securegcm::UKey2Handshake::HandshakeCipher kCipher = - securegcm::UKey2Handshake::HandshakeCipher::P256_SHA512; - -} // namespace +#include "absl/time/clock.h" +#include "absl/time/time.h" namespace location { namespace nearby { namespace connections { - namespace { +constexpr absl::Duration kTimeout = absl::Seconds(15); +constexpr std::int32_t kMaxUkey2VerificationStringLength = 32; +constexpr std::int32_t kTokenLength = 5; +constexpr securegcm::UKey2Handshake::HandshakeCipher kCipher = + securegcm::UKey2Handshake::HandshakeCipher::P256_SHA512; + // Transforms a raw UKEY2 token (which is a random ByteArray that's // kMaxUkey2VerificationStringLength long) into a kTokenLength string that only -// uses A-Z0-9 for each character. -string toHumanReadableString(ConstPtr token) { - string result = Base64Utils::encode(token).substr(0, kTokenLength); +// uses [A-Z], [0-9], '_', '-' for each character. +std::string ToHumanReadableString(const ByteArray& token) { + std::string result = Base64Utils::Encode(token).substr(0, kTokenLength); absl::AsciiStrToUpper(&result); return result; } -template -bool handleEncryptionSuccess( - const string& endpoint_id, Ptr ukey2_handshake, - Ptr::ResultListener> result_listener) { - ScopedPtr> scoped_ukey2_handshake( - ukey2_handshake); - - std::unique_ptr verification_string = - scoped_ukey2_handshake->GetVerificationString( - kMaxUkey2VerificationStringLength); +bool HandleEncryptionSuccess(const std::string& endpoint_id, + std::unique_ptr ukey2, + const EncryptionRunner::ResultListener& listener) { + std::unique_ptr verification_string = + ukey2->GetVerificationString(kMaxUkey2VerificationStringLength); if (verification_string == nullptr) { return false; } - ScopedPtr> raw_authentication_token(MakeConstPtr( - new ByteArray(verification_string->data(), verification_string->size()))); + ByteArray raw_authentication_token(*verification_string); - result_listener->onEncryptionSuccess( - endpoint_id, scoped_ukey2_handshake.release(), - toHumanReadableString(raw_authentication_token.get()), - raw_authentication_token.release()); + listener.on_success_cb(endpoint_id, std::move(ukey2), + ToHumanReadableString(raw_authentication_token), + raw_authentication_token); return true; } -template -class CancelableAlarmRunnable : public Runnable { +void CancelableAlarmRunnable(ClientProxy* client, + const std::string& endpoint_id, + EndpointChannel* endpoint_channel) { + NEARBY_LOG(INFO, + "Timing out encryption for client %" PRId64 + " to endpoint %s after %" PRId64 " ms", + client->GetClientId(), endpoint_id.c_str(), + static_cast(absl::ToInt64Milliseconds(kTimeout))); + endpoint_channel->Close(); +} + +class ServerRunnable final { public: - CancelableAlarmRunnable(Ptr> client_proxy, - const string& endpoint_id, - Ptr endpoint_channel) - : client_proxy_(client_proxy), - endpoint_id_(endpoint_id), - endpoint_channel_(endpoint_channel) {} - - void run() override { - NEARBY_LOG(INFO, - "Timing out encryption for client %" PRId64 - " to endpoint %s after %" PRId64 " ms", - client_proxy_->getClientId(), endpoint_id_.c_str(), - kTimeoutMillis); - endpoint_channel_->close(); - } - - private: - Ptr> client_proxy_; - const string endpoint_id_; - Ptr endpoint_channel_; -}; - -template -class ServerRunnable : public Runnable { - public: - ServerRunnable(Ptr> client_proxy, - Ptr alarm_executor, - const string& endpoint_id, - Ptr endpoint_channel, - Ptr::ResultListener> - encryption_result_listener) - : client_proxy_(client_proxy), + ServerRunnable(ClientProxy* client, ScheduledExecutor* alarm_executor, + const std::string& endpoint_id, EndpointChannel* channel, + EncryptionRunner::ResultListener&& listener) + : client_(client), alarm_executor_(alarm_executor), endpoint_id_(endpoint_id), - endpoint_channel_(endpoint_channel), - encryption_result_listener_(encryption_result_listener) {} + channel_(channel), + listener_(std::move(listener)) {} - void run() override { + void operator()() const { CancelableAlarm timeout_alarm( - "EncryptionRunner.startServer() timeout", - MakePtr(new CancelableAlarmRunnable( - client_proxy_, endpoint_id_, endpoint_channel_)), - kTimeoutMillis, alarm_executor_); + "EncryptionRunner.StartServer() timeout", + [this]() { CancelableAlarmRunnable(client_, endpoint_id_, channel_); }, + kTimeout, alarm_executor_); std::unique_ptr server = securegcm::UKey2Handshake::ForResponder(kCipher); - // Java code throws a HandshakeException. if (server == nullptr) { - logException(); - handleHandshakeOrIOException(&timeout_alarm); + LogException(); + HandleHandshakeOrIoException(&timeout_alarm); return; } // Message 1 (Client Init) - ExceptionOr> client_init = endpoint_channel_->read(); + ExceptionOr client_init = channel_->Read(); if (!client_init.ok()) { - if (Exception::IO == client_init.exception()) { - logException(); - handleHandshakeOrIOException(&timeout_alarm); - return; - } + LogException(); + HandleHandshakeOrIoException(&timeout_alarm); + return; } - ScopedPtr> scoped_client_init(client_init.result()); - securegcm::UKey2Handshake::ParseResult parse_result = - server->ParseHandshakeMessage( - string(scoped_client_init->getData(), scoped_client_init->size())); + server->ParseHandshakeMessage(std::string(client_init.result())); // Java code throws a HandshakeException / AlertException. if (!parse_result.success) { - logException(); + LogException(); if (parse_result.alert_to_send != nullptr) { - handleAlertException(parse_result); + HandleAlertException(parse_result); } - handleHandshakeOrIOException(&timeout_alarm); + HandleHandshakeOrIoException(&timeout_alarm); return; } - NEARBY_LOG(INFO, "In startServer(), read UKEY2 Message 1 from endpoint %s", + NEARBY_LOG(INFO, "In StartServer(), read UKEY2 Message 1 from endpoint %s", endpoint_id_.c_str()); // Message 2 (Server Init) - std::unique_ptr server_init = server->GetNextHandshakeMessage(); + std::unique_ptr server_init = + server->GetNextHandshakeMessage(); // Java code throws a HandshakeException. if (server_init == nullptr) { - logException(); - handleHandshakeOrIOException(&timeout_alarm); + LogException(); + HandleHandshakeOrIoException(&timeout_alarm); return; } - Exception::Value write_exception = endpoint_channel_->write( - MakeConstPtr(new ByteArray(server_init->data(), server_init->size()))); - if (Exception::NONE != write_exception) { - if (Exception::IO == write_exception) { - logException(); - handleHandshakeOrIOException(&timeout_alarm); - return; - } + Exception write_exception = + channel_->Write(ByteArray(std::move(*server_init))); + if (!write_exception.Ok()) { + LogException(); + HandleHandshakeOrIoException(&timeout_alarm); + return; } - NEARBY_LOG(INFO, "In startServer(), wrote UKEY2 Message 2 to endpoint %s", + NEARBY_LOG(INFO, "In StartServer(), wrote UKEY2 Message 2 to endpoint %s", endpoint_id_.c_str()); // Message 3 (Client Finish) - ExceptionOr> client_finish = endpoint_channel_->read(); + ExceptionOr client_finish = channel_->Read(); if (!client_finish.ok()) { - if (Exception::IO == client_finish.exception()) { - logException(); - handleHandshakeOrIOException(&timeout_alarm); - return; - } - } - - ScopedPtr> scoped_client_finish(client_finish.result()); - parse_result = server->ParseHandshakeMessage( - string(scoped_client_finish->getData(), scoped_client_finish->size())); - - // Java code throws an AlertException or a HandshakeException. - if (!parse_result.success) { - logException(); - if (parse_result.alert_to_send != nullptr) { - handleAlertException(parse_result); - } - handleHandshakeOrIOException(&timeout_alarm); + LogException(); + HandleHandshakeOrIoException(&timeout_alarm); return; } - NEARBY_LOG(INFO, "In startServer(), read UKEY2 Message 3 from endpoint %s", + parse_result = + server->ParseHandshakeMessage(std::string(client_finish.result())); + + // Java code throws an AlertException or a HandshakeException. + if (!parse_result.success) { + LogException(); + if (parse_result.alert_to_send != nullptr) { + HandleAlertException(parse_result); + } + HandleHandshakeOrIoException(&timeout_alarm); + return; + } + + NEARBY_LOG(INFO, "In StartServer(), read UKEY2 Message 3 from endpoint %s", endpoint_id_.c_str()); - timeout_alarm.cancel(); + timeout_alarm.Cancel(); - if (!handleEncryptionSuccess(endpoint_id_, - MakePtr(server.release()), - encryption_result_listener_.get())) { - logException(); - handleHandshakeOrIOException(&timeout_alarm); + if (!HandleEncryptionSuccess(endpoint_id_, std::move(server), listener_)) { + LogException(); + HandleHandshakeOrIoException(&timeout_alarm); return; } } private: - void logException() { - NEARBY_LOG(ERROR, "In startServer(), UKEY2 failed with endpoint %s", + void LogException() const { + NEARBY_LOG(ERROR, "In StartServer(), UKEY2 failed with endpoint %s", endpoint_id_.c_str()); } - void handleHandshakeOrIOException(CancelableAlarm* timeout_alarm) { - timeout_alarm->cancel(); - encryption_result_listener_->onEncryptionFailure(endpoint_id_, - endpoint_channel_); + void HandleHandshakeOrIoException(CancelableAlarm* timeout_alarm) const { + timeout_alarm->Cancel(); + listener_.on_failure_cb(endpoint_id_, channel_); } - void handleAlertException( - const securegcm::UKey2Handshake::ParseResult& parse_result) { - Exception::Value write_exception = endpoint_channel_->write( - MakeConstPtr(new ByteArray(parse_result.alert_to_send->data(), - parse_result.alert_to_send->size()))); - if (Exception::NONE != write_exception) { - if (Exception::IO == write_exception) { - NEARBY_LOG(WARNING, - "In startServer(), client %" PRId64 - " failed to pass the alert error message to endpoint %s", - client_proxy_->getClientId(), endpoint_id_.c_str()); - } + void HandleAlertException( + const securegcm::UKey2Handshake::ParseResult& parse_result) const { + Exception write_exception = + channel_->Write(ByteArray(*parse_result.alert_to_send)); + if (!write_exception.Ok()) { + NEARBY_LOG(WARNING, + "In StartServer(), client %" PRId64 + " failed to pass the alert error message to endpoint %s", + client_->GetClientId(), endpoint_id_.c_str()); } } - Ptr> client_proxy_; - Ptr alarm_executor_; - const string endpoint_id_; - Ptr endpoint_channel_; - ScopedPtr::ResultListener>> - encryption_result_listener_; + ClientProxy* client_; + ScheduledExecutor* alarm_executor_; + const std::string endpoint_id_; + EndpointChannel* channel_; + EncryptionRunner::ResultListener listener_; }; -template -class ClientRunnable : public Runnable { +class ClientRunnable final { public: - ClientRunnable(Ptr> client_proxy, - Ptr alarm_executor, - const string& endpoint_id, - Ptr endpoint_channel, - Ptr::ResultListener> - encryption_result_listener) - : client_proxy_(client_proxy), + ClientRunnable(ClientProxy* client, ScheduledExecutor* alarm_executor, + const std::string& endpoint_id, EndpointChannel* channel, + EncryptionRunner::ResultListener&& listener) + : client_(client), alarm_executor_(alarm_executor), endpoint_id_(endpoint_id), - endpoint_channel_(endpoint_channel), - encryption_result_listener_(encryption_result_listener) {} + channel_(channel), + listener_(std::move(listener)) {} - void run() override { + void operator()() const { CancelableAlarm timeout_alarm( "EncryptionRunner.startClient() timeout", - MakePtr(new CancelableAlarmRunnable( - client_proxy_, endpoint_id_, endpoint_channel_)), - kTimeoutMillis, alarm_executor_); + [this]() { CancelableAlarmRunnable(client_, endpoint_id_, channel_); }, + kTimeout, alarm_executor_); - std::unique_ptr client = + std::unique_ptr crypto = securegcm::UKey2Handshake::ForInitiator(kCipher); // Java code throws a HandshakeException. - if (client == nullptr) { - logException(); - handleHandshakeOrIOException(&timeout_alarm); + if (crypto == nullptr) { + LogException(); + HandleHandshakeOrIoException(&timeout_alarm); return; } // Message 1 (Client Init) - std::unique_ptr client_init = client->GetNextHandshakeMessage(); + std::unique_ptr client_init = + crypto->GetNextHandshakeMessage(); // Java code throws a HandshakeException. if (client_init == nullptr) { - logException(); - handleHandshakeOrIOException(&timeout_alarm); + LogException(); + HandleHandshakeOrIoException(&timeout_alarm); return; } - Exception::Value write_init_exception = endpoint_channel_->write( - MakeConstPtr(new ByteArray(client_init->data(), client_init->size()))); - if (Exception::NONE != write_init_exception) { - if (Exception::IO == write_init_exception) { - logException(); - handleHandshakeOrIOException(&timeout_alarm); - return; - } + Exception write_init_exception = channel_->Write(ByteArray(*client_init)); + if (!write_init_exception.Ok()) { + LogException(); + HandleHandshakeOrIoException(&timeout_alarm); + return; } NEARBY_LOG(INFO, "In startClient(), wrote UKEY2 Message 1 to endpoint %s", endpoint_id_.c_str()); // Message 2 (Server Init) - ExceptionOr> server_init = endpoint_channel_->read(); + ExceptionOr server_init = channel_->Read(); if (!server_init.ok()) { - if (Exception::IO == server_init.exception()) { - logException(); - handleHandshakeOrIOException(&timeout_alarm); - return; - } + LogException(); + HandleHandshakeOrIoException(&timeout_alarm); + return; } - ScopedPtr> scoped_server_init(server_init.result()); securegcm::UKey2Handshake::ParseResult parse_result = - client->ParseHandshakeMessage( - string(scoped_server_init->getData(), scoped_server_init->size())); + crypto->ParseHandshakeMessage(std::string(server_init.result())); // Java code throws an AlertException or a HandshakeException. if (!parse_result.success) { - logException(); + LogException(); if (parse_result.alert_to_send != nullptr) { - handleAlertException(parse_result); + HandleAlertException(parse_result); } - handleHandshakeOrIOException(&timeout_alarm); + HandleHandshakeOrIoException(&timeout_alarm); return; } @@ -327,109 +272,95 @@ class ClientRunnable : public Runnable { endpoint_id_.c_str()); // Message 3 (Client Finish) - std::unique_ptr client_finish = client->GetNextHandshakeMessage(); + std::unique_ptr client_finish = + crypto->GetNextHandshakeMessage(); // Java code throws a HandshakeException. if (client_finish == nullptr) { - logException(); - handleHandshakeOrIOException(&timeout_alarm); + LogException(); + HandleHandshakeOrIoException(&timeout_alarm); return; } - Exception::Value write_finish_exception = - endpoint_channel_->write(MakeConstPtr( - new ByteArray(client_finish->data(), client_finish->size()))); - if (Exception::NONE != write_finish_exception) { - if (Exception::IO == write_finish_exception) { - logException(); - handleHandshakeOrIOException(&timeout_alarm); - return; - } + Exception write_finish_exception = + channel_->Write(ByteArray(*client_finish)); + if (!write_finish_exception.Ok()) { + LogException(); + HandleHandshakeOrIoException(&timeout_alarm); + return; } NEARBY_LOG(INFO, "In startClient(), wrote UKEY2 Message 3 to endpoint %s", endpoint_id_.c_str()); - timeout_alarm.cancel(); + timeout_alarm.Cancel(); - if (!handleEncryptionSuccess(endpoint_id_, - MakePtr(client.release()), - encryption_result_listener_.get())) { - logException(); - handleHandshakeOrIOException(&timeout_alarm); + if (!HandleEncryptionSuccess(endpoint_id_, std::move(crypto), listener_)) { + LogException(); + HandleHandshakeOrIoException(&timeout_alarm); return; } } private: - void logException() { + void LogException() const { NEARBY_LOG(ERROR, "In startClient(), UKEY2 failed with endpoint %s", endpoint_id_.c_str()); } - void handleHandshakeOrIOException(CancelableAlarm* timeout_alarm) { - timeout_alarm->cancel(); - encryption_result_listener_->onEncryptionFailure(endpoint_id_, - endpoint_channel_); + void HandleHandshakeOrIoException(CancelableAlarm* timeout_alarm) const { + timeout_alarm->Cancel(); + listener_.on_failure_cb(endpoint_id_, channel_); } - void handleAlertException( - const securegcm::UKey2Handshake::ParseResult& parse_result) { - Exception::Value write_exception = endpoint_channel_->write( - MakeConstPtr(new ByteArray(parse_result.alert_to_send->data(), - parse_result.alert_to_send->size()))); - if (Exception::NONE != write_exception) { - if (Exception::IO == write_exception) { - NEARBY_LOG(WARNING, - "In startClient(), client %" PRId64 - " failed to pass the alert error message to endpoint %s", - client_proxy_->getClientId(), endpoint_id_.c_str()); - } + void HandleAlertException( + const securegcm::UKey2Handshake::ParseResult& parse_result) const { + Exception write_exception = + channel_->Write(ByteArray(*parse_result.alert_to_send)); + if (!write_exception.Ok()) { + NEARBY_LOG(WARNING, + "In startClient(), client %" PRId64 + " failed to pass the alert error message to endpoint %s", + client_->GetClientId(), endpoint_id_.c_str()); } } - Ptr> client_proxy_; - Ptr alarm_executor_; - const string endpoint_id_; - Ptr endpoint_channel_; - ScopedPtr::ResultListener>> - encryption_result_listener_; + ClientProxy* client_; + ScheduledExecutor* alarm_executor_; + const std::string endpoint_id_; + EndpointChannel* channel_; + EncryptionRunner::ResultListener listener_; }; } // namespace -template -EncryptionRunner::EncryptionRunner() - : alarm_executor_(Platform::createScheduledExecutor()), - server_executor_(Platform::createSingleThreadExecutor()), - client_executor_(Platform::createSingleThreadExecutor()) {} - -template -EncryptionRunner::~EncryptionRunner() { +EncryptionRunner::~EncryptionRunner() { // Stop all the ongoing Runnables (as gracefully as possible). - client_executor_->shutdown(); - server_executor_->shutdown(); - alarm_executor_->shutdown(); + client_executor_.Shutdown(); + server_executor_.Shutdown(); + alarm_executor_.Shutdown(); } -template -void EncryptionRunner::startServer( - Ptr> client_proxy, const string& endpoint_id, - Ptr endpoint_channel, - Ptr result_listener) { - server_executor_->execute(MakePtr(new ServerRunnable( - client_proxy, alarm_executor_.get(), endpoint_id, endpoint_channel, - result_listener))); +void EncryptionRunner::StartServer( + ClientProxy* client, const std::string& endpoint_id, + EndpointChannel* endpoint_channel, + EncryptionRunner::ResultListener&& listener) { + server_executor_.Execute( + [runnable{ServerRunnable(client, &alarm_executor_, endpoint_id, + endpoint_channel, std::move(listener))}]() { + runnable(); + }); } -template -void EncryptionRunner::startClient( - Ptr> client_proxy, const string& endpoint_id, - Ptr endpoint_channel, - Ptr result_listener) { - client_executor_->execute(MakePtr(new ClientRunnable( - client_proxy, alarm_executor_.get(), endpoint_id, endpoint_channel, - result_listener))); +void EncryptionRunner::StartClient( + ClientProxy* client, const std::string& endpoint_id, + EndpointChannel* endpoint_channel, + EncryptionRunner::ResultListener&& listener) { + client_executor_.Execute( + [runnable{ClientRunnable(client, &alarm_executor_, endpoint_id, + endpoint_channel, std::move(listener))}]() { + runnable(); + }); } } // namespace connections diff --git a/cpp/core/internal/encryption_runner.h b/cpp/core/internal/encryption_runner.h index 3a2373f8..1e6c365a 100644 --- a/cpp/core/internal/encryption_runner.h +++ b/cpp/core/internal/encryption_runner.h @@ -1,11 +1,14 @@ #ifndef CORE_INTERNAL_ENCRYPTION_RUNNER_H_ #define CORE_INTERNAL_ENCRYPTION_RUNNER_H_ +#include + #include "core/internal/client_proxy.h" #include "core/internal/endpoint_channel.h" -#include "platform/byte_array.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "core/listeners.h" +#include "platform/base/byte_array.h" +#include "platform/public/scheduled_executor.h" +#include "platform/public/single_thread_executor.h" #include "securegcm/ukey2_handshake.h" namespace location { @@ -14,60 +17,56 @@ namespace connections { // Encrypts a connection over UKEY2. // -//

NOTE: Stalled EndpointChannels will be disconnected after {TIMEOUT_MILLIS} -// milliseconds. This is to prevent unverified endpoints from maintaining an +// NOTE: Stalled EndpointChannels will be disconnected after kTimeout. +// This is to prevent unverified endpoints from maintaining an // indefinite connection to us. -template class EncryptionRunner { public: - EncryptionRunner(); + EncryptionRunner() = default; ~EncryptionRunner(); - class ResultListener { - public: - virtual ~ResultListener() {} - + struct ResultListener { // @EncryptionRunnerThread - virtual void onEncryptionSuccess( - const string& endpoint_id, - Ptr ukey2_handshake, - const string& authentication_token, - ConstPtr raw_authentication_token) = 0; + std::function ukey2, + const std::string& auth_token, + const ByteArray& raw_auth_token)> + on_success_cb = + DefaultCallback, + const std::string&, const ByteArray&>(); // Encryption has failed. The remote_endpoint_id and channel are given so // that any pending state can be cleaned up. // - //

We return the EndpointChannel because, at this stage, simultaneous + // We return the EndpointChannel because, at this stage, simultaneous // connections are a possibility. Use this channel to verify that the state // you're cleaning up is for this EndpointChannel, and not state for another // channel to the same endpoint. // // @EncryptionRunnerThread - virtual void onEncryptionFailure(const string& endpoint_id, - Ptr channel) = 0; + std::function + on_failure_cb = DefaultCallback(); }; // @AnyThread - void startServer(Ptr > client_proxy, - const string& endpoint_id, - Ptr endpoint_channel, - Ptr result_listener); + void StartServer(ClientProxy* client, const std::string& endpoint_id, + EndpointChannel* endpoint_channel, + ResultListener&& result_listener); // @AnyThread - void startClient(Ptr > client_proxy, - const string& endpoint_id, - Ptr endpoint_channel, - Ptr result_listener); + void StartClient(ClientProxy* client, const std::string& endpoint_id, + EndpointChannel* endpoint_channel, + ResultListener&& result_listener); private: - ScopedPtr > alarm_executor_; - ScopedPtr > server_executor_; - ScopedPtr > client_executor_; + ScheduledExecutor alarm_executor_; + SingleThreadExecutor server_executor_; + SingleThreadExecutor client_executor_; }; } // namespace connections } // namespace nearby } // namespace location -#include "core/internal/encryption_runner.cc" - #endif // CORE_INTERNAL_ENCRYPTION_RUNNER_H_ diff --git a/cpp/core_v2/internal/encryption_runner_test.cc b/cpp/core/internal/encryption_runner_test.cc similarity index 92% rename from cpp/core_v2/internal/encryption_runner_test.cc rename to cpp/core/internal/encryption_runner_test.cc index 094c0114..32c921a0 100644 --- a/cpp/core_v2/internal/encryption_runner_test.cc +++ b/cpp/core/internal/encryption_runner_test.cc @@ -1,11 +1,11 @@ -#include "core_v2/internal/encryption_runner.h" +#include "core/internal/encryption_runner.h" -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/endpoint_channel.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/pipe.h" -#include "platform_v2/public/system_clock.h" +#include "core/internal/client_proxy.h" +#include "core/internal/endpoint_channel.h" +#include "platform/base/byte_array.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/pipe.h" +#include "platform/public/system_clock.h" #include "proto/connections_enums.pb.h" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/cpp/core/internal/endpoint_channel.h b/cpp/core/internal/endpoint_channel.h index b7e2e52b..3d3e3c65 100644 --- a/cpp/core/internal/endpoint_channel.h +++ b/cpp/core/internal/endpoint_channel.h @@ -2,13 +2,14 @@ #define CORE_INTERNAL_ENDPOINT_CHANNEL_H_ #include +#include -#include "platform/byte_array.h" -#include "platform/exception.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "platform/base/byte_array.h" +#include "platform/base/exception.h" +#include "platform/public/mutex.h" #include "proto/connections_enums.pb.h" #include "securegcm/d2d_connection_context_v1.h" +#include "absl/time/clock.h" namespace location { namespace nearby { @@ -16,52 +17,58 @@ namespace connections { class EndpointChannel { public: - virtual ~EndpointChannel() {} + virtual ~EndpointChannel() = default; - virtual ExceptionOr > - read() = 0; // throws Exception::IO, Exception::INTERRUPTED + using EncryptionContext = ::securegcm::D2DConnectionContextV1; - virtual Exception::Value write( - ConstPtr data) = 0; // throws Exception::IO + virtual ExceptionOr + Read() = 0; // throws Exception::IO, Exception::INTERRUPTED + + virtual Exception Write(const ByteArray& data) = 0; // throws Exception::IO // Closes this EndpointChannel, without tracking the closure in analytics. - virtual void close() = 0; + virtual void Close() = 0; // Closes this EndpointChannel and records the closure with the given reason. - virtual void close(proto::connections::DisconnectionReason reason) = 0; + virtual void Close(proto::connections::DisconnectionReason reason) = 0; // Returns a one-word type descriptor for the concrete EndpointChannel // implementation that can be used in log messages; eg: BLUETOOTH, BLE, WIFI. - virtual string getType() = 0; + virtual std::string GetType() const = 0; // Returns the name of the EndpointChannel. - virtual string getName() = 0; + virtual std::string GetName() const = 0; // Returns the analytics enum representing the medium of this EndpointChannel. - virtual proto::connections::Medium getMedium() = 0; + virtual proto::connections::Medium GetMedium() const = 0; // Enables encryption on the EndpointChannel. - // - // This method takes ownership of the passed-in 'connection_context'. - virtual void enableEncryption( - Ptr connection_context) = 0; + virtual void EnableEncryption(std::shared_ptr context) = 0; // True if the EndpointChannel is currently pausing all writes. - virtual bool isPaused() = 0; + virtual bool IsPaused() const = 0; // Pauses all writes on this EndpointChannel until resume() is called. - virtual void pause() = 0; + virtual void Pause() = 0; // Resumes any writes on this EndpointChannel that were suspended when pause() // was called. - virtual void resume() = 0; + virtual void Resume() = 0; // Returns the timestamp of the last read from this endpoint, or -1 if no // reads have occurred. - // TODO(tracyzhou): Clarify units of timestamp. - virtual std::int64_t getLastReadTimestamp() = 0; + virtual absl::Time GetLastReadTimestamp() const = 0; }; +inline bool operator==(const EndpointChannel& lhs, const EndpointChannel& rhs) { + return (lhs.GetType() == rhs.GetType()) && (lhs.GetName() == rhs.GetName()) && + (lhs.GetMedium() == rhs.GetMedium()); +} + +inline bool operator!=(const EndpointChannel& lhs, const EndpointChannel& rhs) { + return !(lhs == rhs); +} + } // namespace connections } // namespace nearby } // namespace location diff --git a/cpp/core/internal/endpoint_channel_manager.cc b/cpp/core/internal/endpoint_channel_manager.cc index b366fff6..a13e5f97 100644 --- a/cpp/core/internal/endpoint_channel_manager.cc +++ b/cpp/core/internal/endpoint_channel_manager.cc @@ -1,284 +1,138 @@ #include "core/internal/endpoint_channel_manager.h" -#include "core/internal/ble_endpoint_channel.h" -#include "core/internal/bluetooth_endpoint_channel.h" -#include "core/internal/wifi_lan_endpoint_channel.h" -#include "platform/synchronized.h" +#include + +#include "platform/public/logging.h" +#include "platform/public/mutex.h" +#include "platform/public/mutex_lock.h" namespace location { namespace nearby { namespace connections { -EndpointChannelManager::EndpointChannelManager( - Ptr > medium_manager) - : lock_(Platform::createLock()), - medium_manager_(medium_manager), - channel_state_(new ChannelState()) {} - EndpointChannelManager::~EndpointChannelManager() { - Synchronized s(lock_.get()); - - // TODO(tracyzhou): logger.atDebug().log("Initiating shutdown of - // EndpointChannelManager.") - channel_state_.destroy(); - // TODO(tracyzhou): logger.atDebug().log("EndpointChannelManager has shut - // down."); + MutexLock lock(&mutex_); + channel_state_.DestroyAll(); } -Ptr -EndpointChannelManager::createOutgoingBluetoothEndpointChannel( - const string& channel_name, Ptr bluetooth_socket) { - return BluetoothEndpointChannel::createOutgoing(medium_manager_, channel_name, - bluetooth_socket); +void EndpointChannelManager::RegisterChannelForEndpoint( + ClientProxy* client, const std::string& endpoint_id, + std::unique_ptr channel) { + MutexLock lock(&mutex_); + + SetActiveEndpointChannel(client, endpoint_id, std::move(channel)); + + NEARBY_LOG(INFO, "Registered channel: id=%s", endpoint_id.c_str()); } -Ptr -EndpointChannelManager::createIncomingBluetoothEndpointChannel( - const string& channel_name, Ptr bluetooth_socket) { - return BluetoothEndpointChannel::createIncoming(medium_manager_, channel_name, - bluetooth_socket); -} +void EndpointChannelManager::ReplaceChannelForEndpoint( + ClientProxy* client, const std::string& endpoint_id, + std::unique_ptr channel) { + MutexLock lock(&mutex_); -Ptr EndpointChannelManager::createOutgoingBLEEndpointChannel( - const string& channel_name, Ptr ble_socket) { - return BLEEndpointChannel::createOutgoing(medium_manager_, channel_name, - ble_socket); -} - -Ptr EndpointChannelManager::createIncomingBLEEndpointChannel( - const string& channel_name, Ptr ble_socket) { - return BLEEndpointChannel::createIncoming(medium_manager_, channel_name, - ble_socket); -} - -Ptr -EndpointChannelManager::CreateOutgoingWifiLanEndpointChannel( - const string& channel_name, Ptr wifi_lan_socket) { - return WifiLanEndpointChannel::CreateOutgoing( - medium_manager_, channel_name, wifi_lan_socket); -} - -Ptr -EndpointChannelManager::CreateIncomingWifiLanEndpointChannel( - const string& channel_name, Ptr wifi_lan_socket) { - return WifiLanEndpointChannel::CreateIncoming( - medium_manager_, channel_name, wifi_lan_socket); -} - -void EndpointChannelManager::registerChannelForEndpoint( - Ptr > client_proxy, const string& endpoint_id, - Ptr endpoint_channel) { - Synchronized s(lock_.get()); - - // Just in case there was a previous channel, unregister (and, thus, close) it - // now. - unregisterChannelForEndpoint(endpoint_id); - - setActiveEndpointChannel(client_proxy, endpoint_id, endpoint_channel); - - // TODO(tracyzhou): Add logging. -} - -#ifdef BANDWIDTH_UPGRADE_MANAGER_IMPLEMENTED -Ptr EndpointChannelManager::replaceChannelForEndpoint( - Ptr > client_proxy, const string& endpoint_id, - Ptr endpoint_channel) { - Synchronized s(lock_.get()); - - ScopedPtr > scoped_previous_endpoint_channel( - channel_state_->getChannelForEndpoint(endpoint_id)); - if (scoped_previous_endpoint_channel.isNull()) { - // TODO(tracyzhou): Add logging. - return Ptr(); + auto* endpoint = channel_state_.LookupEndpointData(endpoint_id); + if (endpoint != nullptr && endpoint->channel == nullptr) { + NEARBY_LOG(INFO, "Channel is missing while trying to update: id=%s", + endpoint_id.c_str()); } - setActiveEndpointChannel(client_proxy, endpoint_id, endpoint_channel); - - // TODO(tracyzhou): Add logging. - - return scoped_previous_endpoint_channel.release(); + SetActiveEndpointChannel(client, endpoint_id, std::move(channel)); } -#endif -bool EndpointChannelManager::encryptChannelForEndpoint( - const string& endpoint_id, - Ptr encryption_context) { - Synchronized s(lock_.get()); +bool EndpointChannelManager::EncryptChannelForEndpoint( + const std::string& endpoint_id, + std::unique_ptr context) { + MutexLock lock(&mutex_); - ScopedPtr > scoped_endpoint_channel( - channel_state_->getChannelForEndpoint(endpoint_id)); - if (scoped_endpoint_channel.isNull()) { - // TODO(tracyzhou): Add logging. - return false; + channel_state_.UpdateEncryptionContextForEndpoint(endpoint_id, + std::move(context)); + auto* endpoint = channel_state_.LookupEndpointData(endpoint_id); + return channel_state_.EncryptChannel(endpoint); +} + +std::shared_ptr EndpointChannelManager::GetChannelForEndpoint( + const std::string& endpoint_id) { + MutexLock lock(&mutex_); + + auto* endpoint = channel_state_.LookupEndpointData(endpoint_id); + if (endpoint == nullptr) { + NEARBY_LOG(INFO, "No channel info: id=%s", endpoint_id.c_str()); + return {}; } - // We found the requested EndpointChannel, so encrypt it. - encryptChannel(endpoint_id, scoped_endpoint_channel.get(), - encryption_context); - - // Then update 'endpoint_id' to use this new 'encryption_context' here - // onwards. - // - // Remember to manage the memory of the returned - // Ptr responsibly, even though we don't - // need what's returned. - ScopedPtr >( - channel_state_->updateEncryptionContextForEndpoint(endpoint_id, - encryption_context)); - return true; + return endpoint->channel; } -Ptr EndpointChannelManager::getChannelForEndpoint( - const string& endpoint_id) { - Synchronized s(lock_.get()); +void EndpointChannelManager::SetActiveEndpointChannel( + ClientProxy* client, const std::string& endpoint_id, + std::unique_ptr channel) { + // Update the channel first, then encrypt this new channel, if + // crypto context is present. + channel_state_.UpdateChannelForEndpoint(endpoint_id, std::move(channel)); - return channel_state_->getChannelForEndpoint(endpoint_id); + auto* endpoint = channel_state_.LookupEndpointData(endpoint_id); + if (endpoint->IsEncrypted()) channel_state_.EncryptChannel(endpoint); } -void EndpointChannelManager::setActiveEndpointChannel( - Ptr > client_proxy, const string& endpoint_id, - Ptr endpoint_channel) { -#ifdef BANDWIDTH_UPGRADE_MANAGER_IMPLEMENTED - // If the endpoint is currently encrypted, encrypt this new - // 'endpoint_channel'. - if (channel_state_->isEndpointEncrypted(endpoint_id)) { - encryptChannel( - endpoint_id, endpoint_channel, - channel_state_->getEncryptionContextForEndpoint(endpoint_id)); - } -#endif - - // Then update 'endpoint_id' to use this new 'endpoint_channel' here onwards. - // - // Remember to manage the memory of the returned Ptr - // responsibly, even though we don't need what's returned. - ScopedPtr >( - channel_state_->updateChannelForEndpoint(endpoint_id, endpoint_channel)); -} - -void EndpointChannelManager::encryptChannel( - const string& endpoint_id, Ptr endpoint_channel, - Ptr encryption_context) { - // TODO(tracyzhou): Add logging. - endpoint_channel->enableEncryption(encryption_context); +int EndpointChannelManager::GetConnectedEndpointsCount() const { + MutexLock lock(&mutex_); + return channel_state_.GetConnectedEndpointsCount(); } ///////////////////////////////// ChannelState ///////////////////////////////// -EndpointChannelManager::ChannelState::~ChannelState() { - while (!endpoint_id_to_metadata_.empty()) { - typename EndpointIdToMetadataMap::iterator it = - endpoint_id_to_metadata_.begin(); - // TODO(tracyzhou): Add logging. - removeEndpoint(it->first, - proto::connections::DisconnectionReason::SHUTDOWN); +// endpoint - channel endpoint to encrypt +bool EndpointChannelManager::ChannelState::EncryptChannel( + EndpointChannelManager::ChannelState::EndpointData* endpoint) { + if (endpoint != nullptr && endpoint->channel != nullptr && + endpoint->context != nullptr) { + endpoint->channel->EnableEncryption(endpoint->context); + return true; } + return false; } -bool EndpointChannelManager::ChannelState::isEndpointEncrypted( - const string& endpoint_id) { - return !getEncryptionContextForEndpoint(endpoint_id).isNull(); +EndpointChannelManager::ChannelState::EndpointData* +EndpointChannelManager::ChannelState::LookupEndpointData( + const std::string& endpoint_id) { + auto item = endpoints_.find(endpoint_id); + return item != endpoints_.end() ? &item->second : nullptr; } -Ptr -EndpointChannelManager::ChannelState::updateChannelForEndpoint( - const string& endpoint_id, Ptr endpoint_channel) { - Ptr previous_endpoint_channel; - Ptr endpoint_metadata; - - typename EndpointIdToMetadataMap::iterator it = - endpoint_id_to_metadata_.find(endpoint_id); - if (it == endpoint_id_to_metadata_.end()) { - endpoint_metadata = MakePtr(new EndpointMetaData()); - } else { - endpoint_metadata = it->second; - previous_endpoint_channel = endpoint_metadata->endpoint_channel; - } - // Avoid leaks. - ScopedPtr > scoped_previous_endpoint_channel( - previous_endpoint_channel); - - endpoint_metadata->endpoint_channel = endpoint_channel; - endpoint_channel.clear(); - endpoint_id_to_metadata_[endpoint_id] = endpoint_metadata; - - return scoped_previous_endpoint_channel.release(); +void EndpointChannelManager::ChannelState::UpdateChannelForEndpoint( + const std::string& endpoint_id, std::unique_ptr channel) { + // Create EndpointData instance, if necessary, and populate channel. + endpoints_[endpoint_id].channel = std::move(channel); } -Ptr -EndpointChannelManager::ChannelState::updateEncryptionContextForEndpoint( - const string& endpoint_id, - Ptr encryption_context) { - Ptr previous_encryption_context; - Ptr endpoint_metadata; - - typename EndpointIdToMetadataMap::iterator it = - endpoint_id_to_metadata_.find(endpoint_id); - if (it == endpoint_id_to_metadata_.end()) { - endpoint_metadata = MakePtr(new EndpointMetaData()); - } else { - endpoint_metadata = it->second; - previous_encryption_context = endpoint_metadata->encryption_context; - } - // Avoid leaks. - ScopedPtr > - scoped_previous_encryption_context(previous_encryption_context); - - endpoint_metadata->encryption_context = encryption_context; - endpoint_id_to_metadata_[endpoint_id] = endpoint_metadata; - - return scoped_previous_encryption_context.release(); +void EndpointChannelManager::ChannelState::UpdateEncryptionContextForEndpoint( + const std::string& endpoint_id, + std::unique_ptr context) { + // Create EndpointData instance, if necessary, and populate crypto context. + endpoints_[endpoint_id].context = std::move(context); } -bool EndpointChannelManager::ChannelState::removeEndpoint( - const string& endpoint_id, proto::connections::DisconnectionReason reason) { - typename EndpointIdToMetadataMap::iterator it = - endpoint_id_to_metadata_.find(endpoint_id); - if (it == endpoint_id_to_metadata_.end()) { - return false; - } - - it->second->endpoint_channel->close(reason); - it->second.destroy(); - endpoint_id_to_metadata_.erase(it); +bool EndpointChannelManager::ChannelState::RemoveEndpoint( + const std::string& endpoint_id, + proto::connections::DisconnectionReason reason) { + auto item = endpoints_.find(endpoint_id); + if (item == endpoints_.end()) return false; + item->second.disconnect_reason = reason; + endpoints_.erase(item); return true; } -Ptr -EndpointChannelManager::ChannelState::getEncryptionContextForEndpoint( - const string& endpoint_id) { - typename EndpointIdToMetadataMap::iterator it = - endpoint_id_to_metadata_.find(endpoint_id); - if (it == endpoint_id_to_metadata_.end()) { - return Ptr(); - } +bool EndpointChannelManager::UnregisterChannelForEndpoint( + const std::string& endpoint_id) { + MutexLock lock(&mutex_); - return it->second->encryption_context; -} - -Ptr -EndpointChannelManager::ChannelState::getChannelForEndpoint( - const string& endpoint_id) { - typename EndpointIdToMetadataMap::iterator it = - endpoint_id_to_metadata_.find(endpoint_id); - if (it == endpoint_id_to_metadata_.end()) { - return Ptr(); - } - - return it->second->endpoint_channel; -} - -bool EndpointChannelManager::unregisterChannelForEndpoint( - const string& endpoint_id) { - Synchronized s(lock_.get()); - - if (!channel_state_->removeEndpoint( + if (!channel_state_.RemoveEndpoint( endpoint_id, proto::connections::DisconnectionReason::LOCAL_DISCONNECTION)) { return false; } - // TODO(tracyzhou): Add logging. + NEARBY_LOG(INFO, "Unregistered channel: id=%s", endpoint_id.c_str()); return true; } diff --git a/cpp/core/internal/endpoint_channel_manager.h b/cpp/core/internal/endpoint_channel_manager.h index 18ec3641..93dab29e 100644 --- a/cpp/core/internal/endpoint_channel_manager.h +++ b/cpp/core/internal/endpoint_channel_manager.h @@ -1,80 +1,86 @@ #ifndef CORE_INTERNAL_ENDPOINT_CHANNEL_MANAGER_H_ #define CORE_INTERNAL_ENDPOINT_CHANNEL_MANAGER_H_ -#include +#include +#include #include "core/internal/client_proxy.h" #include "core/internal/endpoint_channel.h" -#include "core/internal/medium_manager.h" -#include "platform/api/ble.h" -#include "platform/api/bluetooth_classic.h" -#include "platform/api/lock.h" -#include "platform/api/platform.h" -#include "platform/api/wifi_lan.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "platform/public/logging.h" +#include "platform/public/mutex.h" #include "securegcm/d2d_connection_context_v1.h" +#include "absl/container/flat_hash_map.h" namespace location { namespace nearby { namespace connections { +// NOTE(std::string): +// All the strings in internal class public interfaces should be exchanged as +// const std::string& if they are immutable, and as std::string +// it they are mutable. +// This is to keep all the internal classes compatible with each other, +// and minimize resources spent on the type conversion. +// Project-wide, strings are either passed around as reference (which has +// zero maintenance costs, and sizeof(void*) memory usage => passed around in a +// CPU register), and whenever lifetime etension is required, it must be copied +// to std::string instance (which will again propagate as a const reference +// within it's lifetime domain). + // Manages the communication channels to all the remote endpoints with which we -// are interacting, including serving as a factory for creating said channels. -// -// The factory methods would be static, but for the fact that they need to use -// the MediumManager. -class EndpointChannelManager { +// are interacting. +class EndpointChannelManager final { public: - using Platform = platform::ImplementationPlatform; + using EncryptionContext = EndpointChannel::EncryptionContext; - explicit EndpointChannelManager(Ptr> medium_manager); ~EndpointChannelManager(); - Ptr createOutgoingBluetoothEndpointChannel( - const string& channel_name, Ptr bluetooth_socket); - Ptr createIncomingBluetoothEndpointChannel( - const string& channel_name, Ptr bluetooth_socket); - - Ptr createOutgoingBLEEndpointChannel( - const string& channel_name, Ptr ble_socket); - Ptr createIncomingBLEEndpointChannel( - const string& channel_name, Ptr ble_socket); - - Ptr CreateOutgoingWifiLanEndpointChannel( - const string& channel_name, Ptr wifi_lan_socket); - Ptr CreateIncomingWifiLanEndpointChannel( - const string& channel_name, Ptr wifi_lan_socket); - // Registers the initial EndpointChannel to be associated with an endpoint; // if there already exists a previously-associated EndpointChannel, that will // be closed before continuing the registration. - void registerChannelForEndpoint(Ptr > client_proxy, - const string& endpoint_id, - Ptr endpoint_channel); + void RegisterChannelForEndpoint(ClientProxy* client, + const std::string& endpoint_id, + std::unique_ptr channel) + ABSL_LOCKS_EXCLUDED(mutex_); -#ifdef BANDWIDTH_UPGRADE_MANAGER_IMPLEMENTED // Replaces the EndpointChannel to be associated with an endpoint from here on // in, transferring the encryption context from the previous EndpointChannel // to the newly-provided EndpointChannel. + void ReplaceChannelForEndpoint(ClientProxy* client, + const std::string& endpoint_id, + std::unique_ptr channel) + ABSL_LOCKS_EXCLUDED(mutex_); + + bool EncryptChannelForEndpoint(const std::string& endpoint_id, + std::unique_ptr context) + ABSL_LOCKS_EXCLUDED(mutex_); + + // NOTE(shared_ptr<> usage): // - // Returns the previous EndpointChannel, or null Ptr object if called out of - // order. - Ptr replaceChannelForEndpoint( - Ptr > client_proxy, const string& endpoint_id, - Ptr endpoint_channel); -#endif - - bool encryptChannelForEndpoint( - const string& endpoint_id, - Ptr encryption_context); - - // The returned Ptr will be owned (and destroyed) by the caller. - Ptr getChannelForEndpoint(const string& endpoint_id); + // EndpointChannelManager is holding an EndpointChannel instance; + // GetChannelForEndpoint() is passing ownership over to a worker thread. + // It is not a pointer passing but an ownership passing, to guarantee that + // channel instance will not disappear underneath the feet of a worker thread + // inside EndpointManager [ EndpointManager::EndpointChannelLoopRunnable() ]. + // If it is just a pointer, Channel will get destroyed while in use by a + // worker thread. shared_ptr is a simple and reliable tool to avoid that. + // + // The reason why it can not be std::unique_ptr<> is: there are other code + // paths that expect to be able to read the pointer value multiple times, from + // multiple places (each of them needs "ownership" for the duration of their + // use). EndpointManager::SendTransferFrameBytes() is another such place. + // If EndpointChannelManager replaces the current channel, and any (or both) + // EndpointManager methods that use a channel are running, it is better to + // have a shared ownership. + std::shared_ptr GetChannelForEndpoint( + const std::string& endpoint_id) ABSL_LOCKS_EXCLUDED(mutex_); // Returns true if 'endpoint_id' actually had a registered EndpointChannel. // IOW, a return of false signifies a no-op. - bool unregisterChannelForEndpoint(const string& endpoint_id); + bool UnregisterChannelForEndpoint(const std::string& endpoint_id) + ABSL_LOCKS_EXCLUDED(mutex_); + + int GetConnectedEndpointsCount() const ABSL_LOCKS_EXCLUDED(mutex_); private: // Tracks channel state for all endpoints. This includes what EndpointChannel @@ -82,64 +88,67 @@ class EndpointChannelManager { // been encrypted yet. class ChannelState { public: - ~ChannelState(); + struct EndpointData { + EndpointData() = default; + EndpointData(EndpointData&&) = default; + EndpointData& operator=(EndpointData&&) = default; + ~EndpointData() { + if (channel != nullptr) { + channel->Close(disconnect_reason); + } + } - // True if we have an 'encryption_context' for the endpoint. - bool isEndpointEncrypted(const string& endpoint_id); + // True if we have a 'context' for the endpoint. + bool IsEncrypted() const { return context != nullptr; } - // Stores a new EndpointChannel for the endpoint, returning the previous - // one (if it existed). - Ptr updateChannelForEndpoint( - const string& endpoint_id, Ptr endpoint_channel); - // Stores a new D2DConnectionContextV1 for the endpoint, returning the - // previous one (if it existed). - Ptr updateEncryptionContextForEndpoint( - const string& endpoint_id, - Ptr encryption_context); + std::shared_ptr channel; + std::shared_ptr context; + proto::connections::DisconnectionReason disconnect_reason = + proto::connections::DisconnectionReason::UNKNOWN_DISCONNECTION_REASON; + }; + + ChannelState() = default; + ~ChannelState() { DestroyAll(); } + ChannelState(ChannelState&&) = default; + ChannelState& operator=(ChannelState&&) = default; + + // Provides a way to destroy contents of a container, while holding a lock. + void DestroyAll() { endpoints_.clear(); } + // Return pointer to endpoint data, or nullptr, it not found. + EndpointData* LookupEndpointData(const std::string& endpoint_id); + + // Stores a new EndpointChannel for the endpoint. + // Prevoius one is destroyed, if it existed. + void UpdateChannelForEndpoint(const std::string& endpoint_id, + std::unique_ptr channel); + + // Stores a new EncryptionContext for the endpoint. + // Prevoius one is destroyed, if it existed. + void UpdateEncryptionContextForEndpoint( + const std::string& endpoint_id, + std::unique_ptr context); // Removes all knowledge of this endpoint, cleaning up as necessary. // Returns false if the endpoint was not found. - bool removeEndpoint(const string& endpoint_id, + bool RemoveEndpoint(const std::string& endpoint_id, proto::connections::DisconnectionReason reason); - // Gets the 'encryption_context' for the endpoint. Null if the endpoint was - // not found, or if there is no 'encryption_context' yet. - Ptr getEncryptionContextForEndpoint( - const string& endpoint_id); - // Gets the 'endpoint_channel' for the endpoint. Null if the endpoint was - // not found. - // - // The returned Ptr will be owned (and destroyed) by the caller. - Ptr getChannelForEndpoint(const string& endpoint_id); + bool EncryptChannel(EndpointData* endpoint); + int GetConnectedEndpointsCount() const { return endpoints_.size(); } private: - struct EndpointMetaData { - ~EndpointMetaData() { - encryption_context.destroy(); - endpoint_channel.destroy(); - } - - Ptr endpoint_channel; - Ptr encryption_context; - }; - - // Endpoint ID -> EndpointMetadata. Contains everything we know about the + // Endpoint ID -> EndpointData. Contains everything we know about the // endpoint. - typedef std::map > EndpointIdToMetadataMap; - EndpointIdToMetadataMap endpoint_id_to_metadata_; + absl::flat_hash_map endpoints_; }; - void setActiveEndpointChannel(Ptr > client_proxy, - const string& endpoint_id, - Ptr endpoint_channel); - void encryptChannel( - const string& endpoint_id, Ptr endpoint_channel, - Ptr encryption_context); + void SetActiveEndpointChannel(ClientProxy* client, + const std::string& endpoint_id, + std::unique_ptr channel) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - ScopedPtr > lock_; - - Ptr > medium_manager_; - Ptr channel_state_; + mutable Mutex mutex_; + ChannelState channel_state_ ABSL_GUARDED_BY(mutex_); }; } // namespace connections diff --git a/cpp/core_v2/internal/endpoint_channel_manager_test.cc b/cpp/core/internal/endpoint_channel_manager_test.cc similarity index 84% rename from cpp/core_v2/internal/endpoint_channel_manager_test.cc rename to cpp/core/internal/endpoint_channel_manager_test.cc index 673ed7f1..01d40846 100644 --- a/cpp/core_v2/internal/endpoint_channel_manager_test.cc +++ b/cpp/core/internal/endpoint_channel_manager_test.cc @@ -1,4 +1,4 @@ -#include "core_v2/internal/endpoint_channel_manager.h" +#include "core/internal/endpoint_channel_manager.h" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/cpp/core/internal/endpoint_manager.cc b/cpp/core/internal/endpoint_manager.cc index f6757d06..08779491 100644 --- a/cpp/core/internal/endpoint_manager.cc +++ b/cpp/core/internal/endpoint_manager.cc @@ -1,747 +1,542 @@ #include "core/internal/endpoint_manager.h" +#include #include +#include "core/internal/endpoint_channel.h" #include "core/internal/offline_frames.h" +#include "platform/base/exception.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/logging.h" #include "proto/connections_enums.pb.h" namespace location { namespace nearby { namespace connections { -namespace endpoint_manager { +using ::location::nearby::proto::connections::Medium; + +constexpr absl::Duration EndpointManager::kKeepAliveWriteInterval; +constexpr absl::Duration EndpointManager::kKeepAliveReadTimeout; +constexpr absl::Duration EndpointManager::kProcessEndpointDisconnectionTimeout; +constexpr absl::Time EndpointManager::kInvalidTimestamp; // A Runnable that continuously grabs the most recent EndpointChannel available -// for an endpoint. Override -// EndpointChannelLoopRunnable.execute(EndpointChannel) to interact with the -// EndpointChannel. -template -class EndpointChannelLoopRunnable : public Runnable { - public: - EndpointChannelLoopRunnable(Ptr> endpoint_manager, - const string& runnable_name, - Ptr> client_proxy, - const string& endpoint_id) - : endpoint_manager_(endpoint_manager), - runnable_name_(runnable_name), - client_proxy_(client_proxy), - endpoint_id_(endpoint_id) {} - ~EndpointChannelLoopRunnable() override {} - - void run() override { - // The implication of using the EndpointChannel's medium to identify it is - // that this loop will break if we ever allow creating multiple - // EndpointChannels to the same endpoint over the same medium. - proto::connections::Medium last_failed_endpoint_channel_medium = - proto::connections::UNKNOWN_MEDIUM; - while (true) { - // It's important to keep re-fetching the EndpointChannel for an endpoint - // because it can be changed out from under us (for example, when we - // upgrade from Bluetooth to Wifi). - ScopedPtr> scoped_endpoint_channel( - endpoint_manager_->endpoint_channel_manager_->getChannelForEndpoint( - endpoint_id_)); - if (scoped_endpoint_channel.isNull()) { - // TODO(tracyzhou): Add logging. - break; - } - - // If we're looping back around after a failure, and there's not a new - // EndpointChannel for this endpoint, there's nothing more to do here. - if ((last_failed_endpoint_channel_medium != - proto::connections::UNKNOWN_MEDIUM) && - (scoped_endpoint_channel->getMedium() == - last_failed_endpoint_channel_medium)) { - // TODO(tracyzhou): Add logging. - break; - } - - ExceptionOr keep_using_channel = - useHealthyEndpointChannel(scoped_endpoint_channel.get()); - - if (!keep_using_channel.ok()) { - Exception::Value exception = keep_using_channel.exception(); - if (Exception::IO == exception) { - last_failed_endpoint_channel_medium = - scoped_endpoint_channel->getMedium(); - // TODO(tracyzhou): Add logging. - continue; - } - if (Exception::INTERRUPTED == exception) { - // Thread.currentThread().interrupt(); - // TODO(tracyzhou): Add logging. - break; - } - } - - if (!keep_using_channel.result()) { - // TODO(tracyzhou): Add logging. - break; - } +// for an endpoint. +// +// handler - Called whenever an EndpointChannel is available for endpointId. +// Implementations are expected to read/write freely to the +// EndpointChannel until an Exception::IO is thrown. Once an +// Exception::IO occurs, a check will be performed to see if another +// EndpointChannel is available for the given endpoint and, if so, +// handler(EndpointChannel) will be called again. Return false to exit +// the loop. +void EndpointManager::EndpointChannelLoopRunnable( + const std::string& runnable_name, ClientProxy* client, + const std::string& endpoint_id, CountDownLatch* barrier, + std::function(EndpointChannel*)> handler) { + // EndpointChannelManager will not let multiple channels exist simultaneously + // for the same endpoint_id; it will be closing "old" channels as new ones + // come. (There will be a short overlap). + // Closed channel will return Exception::kIo for any Read, and loop (below) + // will retry and attempt to pick another channel. + // If channel is deleted (no mapping), or it is still the same channel + // (same Medium) on which we got the Exception::kIo, we terminate the loop. + Medium last_failed_medium = Medium::UNKNOWN_MEDIUM; + while (true) { + // It's important to keep re-fetching the EndpointChannel for an endpoint + // because it can be changed out from under us (for example, when we + // upgrade from Bluetooth to Wifi). + std::shared_ptr channel = + channel_manager_->GetChannelForEndpoint(endpoint_id); + if (channel == nullptr) { + NEARBY_LOG(INFO, "Endpoint channel is nullptr, bail out."); + break; } - // Always clear out all state related to this endpoint before terminating - // this thread. - endpoint_manager_->discardEndpoint(client_proxy_, endpoint_id_); - } + // If we're looping back around after a failure, and there's not a new + // EndpointChannel for this endpoint, there's nothing more to do here. + if ((last_failed_medium != Medium::UNKNOWN_MEDIUM) && + (channel->GetMedium() == last_failed_medium)) { + NEARBY_LOG( + INFO, "No new endpoint channel is found after a failure, exit loop."); + break; + } - // Called whenever an EndpointChannel is available for endpointId. - // Implementations are expected to read/write freely to the EndpointChannel - // until an Exception::IO is thrown. Once an Exception::IO occurs, a check - // will be performed to see if another EndpointChannel is available for the - // given endpoint and, if so, useHealthyEndpointChannel(EndpointChannel) will - // be called again. - // - //

Return false to exit the loop. - virtual ExceptionOr useHealthyEndpointChannel( - Ptr endpoint_channel) = 0; // throws Exception::IO, - // Exception::INTERRUPTED + ExceptionOr keep_using_channel = handler(channel.get()); - protected: - Ptr> endpoint_manager_; - const string runnable_name_; - Ptr> client_proxy_; - const string endpoint_id_; -}; - -template -class ReaderRunnable : public EndpointChannelLoopRunnable { - public: - ReaderRunnable(Ptr> endpoint_manager, - Ptr> client_proxy, - const string& endpoint_id) - : EndpointChannelLoopRunnable(endpoint_manager, "Read", - client_proxy, endpoint_id) {} - - // @EndpointManagerReaderThread - ExceptionOr useHealthyEndpointChannel( - Ptr endpoint_channel) override { - // Read as much as we can from the healthy EndpointChannel - when it is no - // longer in good shape (i.e. our read from it throws an Exception), our - // super class will loop back around and try our luck in case there's been - // a replacement for this endpoint since we last checked with the - // EndpointChannelManager. - while (true) { - ExceptionOr> read_bytes = endpoint_channel->read(); - if (!read_bytes.ok()) { - if (Exception::INVALID_PROTOCOL_BUFFER == read_bytes.exception()) { - // TODO(reznor): logger.atDebug().withCause(e).log("EndpointManager - // failed to decode message from endpoint %s on channel %s, - // discarding.", endpointId, endpointChannel.getType()); - continue; - } else if (Exception::IO == read_bytes.exception()) { - return ExceptionOr(read_bytes.exception()); - } - } - ScopedPtr> scoped_read_bytes(read_bytes.result()); - - ExceptionOr> offline_frame = - OfflineFrames::fromBytes(scoped_read_bytes.get()); - if (!offline_frame.ok()) { - if (Exception::INVALID_PROTOCOL_BUFFER == offline_frame.exception()) { - // TODO(reznor): logger.atDebug().withCause(e).log("EndpointManager - // received an invalid OfflineFrame from endpoint %s on channel %s, - // discarding.", endpointId, endpointChannel.getType()); - continue; - } - } - ScopedPtr> scoped_offline_frame( - offline_frame.result()); - - // Route the incoming offlineFrame to its registered processor. - V1Frame::FrameType frame_type = - OfflineFrames::getFrameType(scoped_offline_frame.get()); - Ptr::IncomingOfflineFrameProcessor> - incoming_offline_frame_processor = - this->endpoint_manager_->getOfflineFrameProcessor(frame_type); - if (incoming_offline_frame_processor.isNull()) { - // TODO(tracyzhou): Add logging. + if (!keep_using_channel.ok()) { + Exception exception = keep_using_channel.GetException(); + if (exception.Raised(Exception::kIo)) { + last_failed_medium = channel->GetMedium(); + NEARBY_LOG(INFO, "Endpoint channel IO exception; last_failed_medium=%d", + last_failed_medium); continue; } - - incoming_offline_frame_processor->processIncomingOfflineFrame( - scoped_offline_frame.release(), this->endpoint_id_, - this->client_proxy_, endpoint_channel->getMedium()); - } - } -}; - -template -class KeepAliveManagerRunnable : public EndpointChannelLoopRunnable { - public: - KeepAliveManagerRunnable(Ptr> endpoint_manager, - Ptr> client_proxy, - const string& endpoint_id) - : EndpointChannelLoopRunnable( - endpoint_manager, "KeepAliveManager", client_proxy, endpoint_id) {} - - // @EndpointManagerKeepAliveThread - ExceptionOr useHealthyEndpointChannel( - Ptr endpoint_channel) override { - // Check if it has been too long since we received a frame from our - // endpoint. - if ((endpoint_channel->getLastReadTimestamp() != -1) && - ((endpoint_channel->getLastReadTimestamp() + - EndpointManager::kKeepAliveReadTimeoutMillis) < - this->endpoint_manager_->system_clock_->elapsedRealtime())) { - // TODO(tracyzhou): Add logging. - return ExceptionOr(false); - } - - // Attempt to send the KeepAlive frame over the endpoint channel - if the - // write fails, our super class will loop back around and try our luck again - // in case there's been a replacement for this endpoint. - Exception::Value write_exception = - endpoint_channel->write(OfflineFrames::forKeepAlive()); - if (Exception::NONE != write_exception) { - if (Exception::IO == write_exception) { - return ExceptionOr(write_exception); + if (exception.Raised(Exception::kInterrupted)) { + break; } } - // We sleep as the very last step because we want to minimize the caching of - // the EndpointChannel. If we do hold on to the EndpointChannel, and it's - // switched out from under us in BandwidthUpgradeManager, our write will - // trigger an erroneous write to the encryption context that will cascade - // into all our remote endpoint's future reads failing. - Exception::Value sleep_exception = - this->endpoint_manager_->thread_utils_->sleep( - EndpointManager::kKeepAliveWriteIntervalMillis); - if (Exception::NONE != sleep_exception) { - if (Exception::INTERRUPTED == sleep_exception) { - return ExceptionOr(sleep_exception); + if (!keep_using_channel.result()) { + NEARBY_LOG(INFO, "Dropping current channel: last medium=%d", + last_failed_medium); + break; + } + } + // Indicate we're out of the loop and it is ok to schedule another instance + // if needed. + NEARBY_LOG(INFO, "Worker going down; name=%s; id=%s", runnable_name.c_str(), + endpoint_id.c_str()); + barrier->CountDown(); + + // Always clear out all state related to this endpoint before terminating + // this thread. + DiscardEndpoint(client, endpoint_id); + NEARBY_LOG(INFO, "Worker done; name=%s; id=%s", runnable_name.c_str(), + endpoint_id.c_str()); +} + +ExceptionOr EndpointManager::HandleData( + const std::string& endpoint_id, ClientProxy* client, + EndpointChannel* endpoint_channel) { + // Read as much as we can from the healthy EndpointChannel - when it is no + // longer in good shape (i.e. our read from it throws an Exception), our + // super class will loop back around and try our luck in case there's been + // a replacement for this endpoint since we last checked with the + // EndpointChannelManager. + while (true) { + ExceptionOr bytes = endpoint_channel->Read(); + if (!bytes.ok()) { + NEARBY_LOG(INFO, "Stop reading on read-time exception: %d", + bytes.exception()); + return ExceptionOr(bytes.exception()); + } + ExceptionOr wrapped_frame = parser::FromBytes(bytes.result()); + if (!wrapped_frame.ok()) { + if (wrapped_frame.GetException().Raised( + Exception::kInvalidProtocolBuffer)) { + NEARBY_LOG(INFO, "Failed to decode; endpoint=%s; channel=%s; skip", + endpoint_id.c_str(), endpoint_channel->GetType().c_str()); + continue; + } else { + NEARBY_LOG(INFO, "Stop reading on parse-time exception: %d", + wrapped_frame.exception()); + return ExceptionOr(wrapped_frame.exception()); } } + OfflineFrame& frame = wrapped_frame.result(); - return ExceptionOr(true); + // Route the incoming offlineFrame to its registered processor. + V1Frame::FrameType frame_type = parser::GetFrameType(frame); + EndpointManager::FrameProcessor* frame_processor = + GetFrameProcessor(frame_type); + if (frame_processor == nullptr) { + // report messages without handlers, except KEEP_ALIVE, which has + // no explicit handler. + if (frame_type == V1Frame::KEEP_ALIVE) { + NEARBY_LOG(INFO, "KeepAlive message for: id=%s", endpoint_id.c_str()); + } else if (frame_type == V1Frame::DISCONNECTION) { + NEARBY_LOG(INFO, "Disconnect message for: id=%s", endpoint_id.c_str()); + endpoint_channel->Close(); + } else { + NEARBY_LOG(ERROR, "Unhandled message: id=%s, type=%d", + endpoint_id.c_str(), frame_type); + } + continue; + } + + frame_processor->OnIncomingFrame(frame, endpoint_id, client, + endpoint_channel->GetMedium()); } -}; +} -template -class RegisterIncomingOfflineFrameProcessorRunnable : public Runnable { - public: - RegisterIncomingOfflineFrameProcessorRunnable( - Ptr> endpoint_manager, - V1Frame::FrameType frame_type, - Ptr::IncomingOfflineFrameProcessor> - processor) - : endpoint_manager_(endpoint_manager), - frame_type_(frame_type), - processor_(processor) {} +ExceptionOr EndpointManager::HandleKeepAlive( + EndpointChannel* endpoint_channel) { + // Check if it has been too long since we received a frame from our + // endpoint. + auto last_read_time = endpoint_channel->GetLastReadTimestamp(); + if (last_read_time != kInvalidTimestamp && + SystemClock::ElapsedRealtime() > + (last_read_time + EndpointManager::kKeepAliveReadTimeout)) { + NEARBY_LOG(INFO, "Receive timeout expired; aborting KeepAlive worker."); + return ExceptionOr(false); + } - void run() override { - typename EndpointManager< - Platform>::IncomingOfflineFrameProcessorsMap::iterator it = - endpoint_manager_->incoming_offline_frame_processors_.find(frame_type_); - if (it != endpoint_manager_->incoming_offline_frame_processors_.end()) { - // TODO(tracyzhou): Add logging. - it->second = processor_; + // Attempt to send the KeepAlive frame over the endpoint channel - if the + // write fails, our super class will loop back around and try our luck again + // in case there's been a replacement for this endpoint. + Exception write_exception = endpoint_channel->Write(parser::ForKeepAlive()); + if (!write_exception.Ok()) { + return ExceptionOr(write_exception); + } + + // We sleep as the very last step because we want to minimize the caching of + // the EndpointChannel. If we do hold on to the EndpointChannel, and it's + // switched out from under us in BandwidthUpgradeManager, our write will + // trigger an erroneous write to the encryption context that will cascade + // into all our remote endpoint's future reads failing. + Exception sleep_exception = + SystemClock::Sleep(EndpointManager::kKeepAliveWriteInterval); + if (!sleep_exception.Ok()) { + return ExceptionOr(sleep_exception); + } + + return ExceptionOr(true); +} + +bool operator==(const EndpointManager::FrameProcessor& lhs, + const EndpointManager::FrameProcessor& rhs) { + // We're comparing addresses because these objects are callbacks which need to + // be matched by exact instances. + return &lhs == &rhs; +} + +bool operator<(const EndpointManager::FrameProcessor& lhs, + const EndpointManager::FrameProcessor& rhs) { + // We're comparing addresses because these objects are callbacks which need to + // be matched by exact instances. + return &lhs < &rhs; +} + +EndpointManager::EndpointManager(EndpointChannelManager* manager) + : channel_manager_(manager) {} + +EndpointManager::~EndpointManager() { + NEARBY_LOG(INFO, "EndpointManager going down"); + CountDownLatch latch(1); + RunOnEndpointManagerThread([this, &latch]() { + NEARBY_LOG(INFO, "Bringing down endpoints"); + for (auto& item : endpoints_) { + const std::string& endpoint_id = item.first; + EndpointState& state = item.second; + // This will close the channel; all workers will sense that and + // terminate. + channel_manager_->UnregisterChannelForEndpoint(endpoint_id); + state.barrier.Await(); + } + latch.CountDown(); + }); + latch.Await(); + NEARBY_LOG(INFO, "Bringing down worker threads"); + + // Stop all the ongoing Runnables (as gracefully as possible). + // Order matters: bring worker pools down first; serial_executor_ thread + // should go last, since workers schedule jobs there even during shutdown. + handlers_executor_.Shutdown(); + keep_alive_executor_.Shutdown(); + NEARBY_LOG(INFO, "Bringing down control thread"); + serial_executor_.Shutdown(); + NEARBY_LOG(INFO, "EndpointManager is down"); +} + +EndpointManager::FrameProcessor::Handle EndpointManager::RegisterFrameProcessor( + V1Frame::FrameType frame_type, EndpointManager::FrameProcessor* processor) { + const FrameProcessor::Handle handle = processor; + CountDownLatch latch(1); + RunOnEndpointManagerThread([this, frame_type, &latch, processor]() { + auto it = frame_processors_.find(frame_type); + if (it != frame_processors_.end()) { + NEARBY_LOGS(INFO) << "Frame processor found: updated; type=" << frame_type + << "; processor=" << processor << "; self=" << this; + it->second = processor; } else { - endpoint_manager_->incoming_offline_frame_processors_.insert( - std::make_pair(frame_type_, processor_)); + NEARBY_LOGS(INFO) << "Frame processor added; type=" << frame_type + << "; processor=" << processor << "; self=" << this; + frame_processors_.emplace(frame_type, processor); } - } + latch.CountDown(); + }); + latch.Await(); + return handle; +} - private: - Ptr> endpoint_manager_; - const V1Frame::FrameType frame_type_; - Ptr::IncomingOfflineFrameProcessor> - processor_; -}; - -template -class UnregisterIncomingOfflineFrameProcessorRunnable : public Runnable { - public: - UnregisterIncomingOfflineFrameProcessorRunnable( - Ptr> endpoint_manager, - V1Frame::FrameType frame_type, - Ptr::IncomingOfflineFrameProcessor> - processor) - : endpoint_manager_(endpoint_manager), - frame_type_(frame_type), - processor_(processor) {} - - void run() override { - typename EndpointManager< - Platform>::IncomingOfflineFrameProcessorsMap::iterator it = - endpoint_manager_->incoming_offline_frame_processors_.find(frame_type_); - if (it != endpoint_manager_->incoming_offline_frame_processors_.end()) { - if (it->second != processor_) { - // TODO(tracyzhou): Add logging. - return; - } - - endpoint_manager_->incoming_offline_frame_processors_.erase(it); +void EndpointManager::UnregisterFrameProcessor(V1Frame::FrameType frame_type, + const void* handle, bool sync) { + NEARBY_LOGS(INFO) << "UnregisterFrameProcessor [enter]: handle=" << handle; + if (handle == nullptr) return; + CountDownLatch latch(1); + RunOnEndpointManagerThread([this, frame_type, handle, &latch, sync]() { + auto it = frame_processors_.find(frame_type); + if (it == frame_processors_.end()) { + NEARBY_LOGS(INFO) << "UnregisterFrameProcessor [not found]: handle=" + << handle; + if (sync) latch.CountDown(); + return; } + NEARBY_LOGS(INFO) << "UnregisterFrameProcessor [found]: handle=" << handle; + if (it->second == handle) { + frame_processors_.erase(it); + NEARBY_LOGS(INFO) << "Unregistered: type=" << frame_type + << "; processor=" << handle << "; self=" << this; + } else { + NEARBY_LOG(INFO, + "Failed to unregister: type=%d; handle mismatch: passed=%p, " + "expected=%p", + frame_type, handle, it->second); + } + if (sync) latch.CountDown(); + }); + if (sync) { + latch.Await(); + NEARBY_LOGS(INFO) << "Unregistered [sync done]: type=" << frame_type + << "; processor=" << handle << "; self=" << this; } +} - private: - Ptr> endpoint_manager_; - const V1Frame::FrameType frame_type_; - Ptr::IncomingOfflineFrameProcessor> - processor_; -}; +EndpointManager::FrameProcessor* EndpointManager::GetFrameProcessor( + V1Frame::FrameType frame_type) { + EndpointManager::FrameProcessor* processor = nullptr; + CountDownLatch latch(1); + RunOnEndpointManagerThread([this, frame_type, &processor, &latch]() { + auto it = frame_processors_.find(frame_type); + if (it != frame_processors_.end()) { + processor = it->second; + } + latch.CountDown(); + }); + latch.Await(); + NEARBY_LOG(INFO, "GetFrameProcessor: type=%d; processor=%p", frame_type, + processor); + return processor; +} -template -class RegisterEndpointRunnable : public Runnable { - public: - RegisterEndpointRunnable( - Ptr> endpoint_manager, - Ptr> client_proxy, const string& endpoint_id, - const string& endpoint_name, const string& authentication_token, - ConstPtr raw_authentication_token, bool is_incoming, - Ptr endpoint_channel, - Ptr connection_lifecycle_listener, - Ptr latch) - : endpoint_manager_(endpoint_manager), - client_proxy_(client_proxy), - endpoint_id_(endpoint_id), - endpoint_name_(endpoint_name), - authentication_token_(authentication_token), - raw_authentication_token_(raw_authentication_token), - is_incoming_(is_incoming), - endpoint_channel_(endpoint_channel), - connection_lifecycle_listener_(connection_lifecycle_listener), - latch_(latch) {} +void EndpointManager::EnsureWorkersTerminated(const std::string& endpoint_id) { + auto item = endpoints_.find(endpoint_id); + if (item != endpoints_.end()) { + // If another instance of data and keep-alive handlers is running, it will + // terminate soon; we should block until it happens. + EndpointState& endpoint_state = item->second; + NEARBY_LOGS(INFO) << "Waiting for workers to terminate for id: " + << endpoint_id; + endpoint_state.barrier.Await(); + endpoints_.erase(item); + NEARBY_LOGS(INFO) << "Workers terminated for id: " << endpoint_id; + } else { + NEARBY_LOGS(INFO) << "EndpointState not found for id: " << endpoint_id; + } +} - void run() override { - endpoint_manager_->endpoint_channel_manager_->registerChannelForEndpoint( - client_proxy_, endpoint_id_, endpoint_channel_); +void EndpointManager::RegisterEndpoint(ClientProxy* client, + const std::string& endpoint_id, + const ConnectionResponseInfo& info, + const ConnectionOptions& options, + std::unique_ptr channel, + const ConnectionListener& listener) { + CountDownLatch latch(1); - // For every endpoint, there's one Reader instance running on the - // EndpointManagerReaderThread. This instance reads from the endpoint and - // delegates incoming frames to various IncomingOfflineFrameProcessors. - // Once the frame has been properly handled, it starts reading again for the - // next frame. If the Reader fails its read and no other EndpointChannels - // are available for this endpoint, a disconnection will be initiated. - endpoint_manager_->startEndpointReader(MakePtr(new ReaderRunnable( - endpoint_manager_, client_proxy_, endpoint_id_))); + // NOTE (unique_ptr<> capture): + // std::unique_ptr<> is not copyable, so we can not pass it to + // lambda capture, because lambda eventually is converted to std::function<>. + // Instead, we release() a pointer, and pass a raw pointer, which is copyalbe. + // We ignore the risk of job not scheduled (and an associated risk of memory + // leak), because this may only happen during service shutdown. + RunOnEndpointManagerThread([this, client, channel = channel.release(), + &endpoint_id, &info, &options, &listener, + &latch]() { + // Pass ownership of channel to EndpointChannelManager + NEARBY_LOG(INFO, "Registering endpoint with channel manager: id=%s", + endpoint_id.c_str()); + channel_manager_->RegisterChannelForEndpoint( + client, endpoint_id, std::unique_ptr(channel)); - // For every endpoint, there's one KeepAliveManager instance running on the - // EndpointManagerKeepAliveThread. This instance will periodically - // send out a ping* to the endpoint while listening for an incoming pong**. - // If it fails to send the ping, or if no pong is heard within - // kKeepAliveReadTimeoutMillis milliseconds, it initiates a + EnsureWorkersTerminated(endpoint_id); + EndpointState& endpoint_state = + endpoints_.emplace(endpoint_id, EndpointState()).first->second; + endpoint_state.client = client; + + NEARBY_LOG(INFO, "Starting workers: id=%s", endpoint_id.c_str()); + // For every endpoint, there's normally only one Read handler instance + // running on the handlers_executor_ pool. This instance reads data from the + // endpoint and delegates incoming frames to various FrameProcessors. + // Once the frame has been properly handled, it starts reading again for + // the next frame. If the handler fails its read and no other + // EndpointChannels are available for this endpoint, a disconnection + // will be initiated. + StartEndpointReader( + [this, client, endpoint_id, barrier = &endpoint_state.barrier]() { + EndpointChannelLoopRunnable( + "Read", client, endpoint_id, barrier, + [this, client, endpoint_id](EndpointChannel* channel) { + return HandleData(endpoint_id, client, channel); + }); + }); + + // For every endpoint, there's only one KeepAliveManager instance + // running on the keep_alive_executor_ pool. This instance will + // periodically send out a ping* to the endpoint while listening for an + // incoming pong**. If it fails to send the ping, or if no pong is heard + // within kKeepAliveReadTimeoutMillis milliseconds, it initiates a // disconnection. // - // (*) Bluetooth requires a constant outgoing stream of messages. If there's - // silence, Android will break the socket. This is why we ping. + // (*) Bluetooth requires a constant outgoing stream of messages. If + // there's silence, Android will break the socket. This is why we ping. // (**) Wifi Hotspots can fail to notice a connection has been lost, and - // they will happily keep writing to /dev/null. This is why we listen for - // the pong. - endpoint_manager_->startEndpointKeepAliveManager( - MakePtr(new KeepAliveManagerRunnable( - endpoint_manager_, client_proxy_, endpoint_id_))); - // TODO(tracyzhou): Add logging. + // they will happily keep writing to /dev/null. This is why we listen + // for the pong. + StartEndpointKeepAliveManager([this, client, endpoint_id, + barrier = &endpoint_state.barrier]() { + EndpointChannelLoopRunnable("KeepAliveManager", client, endpoint_id, + barrier, [this](EndpointChannel* channel) { + return HandleKeepAlive(channel); + }); + }); + NEARBY_LOG(INFO, "Workers started, notifying client; id=%s", + endpoint_id.c_str()); - // It's now time to let the client know of this new connection so that they - // can accept or reject it. - client_proxy_->onConnectionInitiated( - endpoint_id_, endpoint_name_, authentication_token_, - raw_authentication_token_.release(), is_incoming_, - connection_lifecycle_listener_.release()); - latch_->countDown(); - } - - private: - Ptr> endpoint_manager_; - Ptr> client_proxy_; - const string endpoint_id_; - const string endpoint_name_; - const string authentication_token_; - ScopedPtr> raw_authentication_token_; - const bool is_incoming_; - Ptr endpoint_channel_; - ScopedPtr> connection_lifecycle_listener_; - Ptr latch_; -}; - -template -class UnregisterEndpointRunnable : public Runnable { - public: - UnregisterEndpointRunnable(Ptr> endpoint_manager, - Ptr> client_proxy, - const string& endpoint_id, - Ptr latch) - : endpoint_manager_(endpoint_manager), - client_proxy_(client_proxy), - endpoint_id_(endpoint_id), - latch_(latch) {} - - void run() override { - endpoint_manager_->removeEndpoint( - client_proxy_, endpoint_id_, /*send_disconnection_notification=*/false); - - latch_->countDown(); - } - - private: - Ptr> endpoint_manager_; - Ptr> client_proxy_; - const string endpoint_id_; - Ptr latch_; -}; - -template -class DiscardEndpointRunnable : public Runnable { - public: - DiscardEndpointRunnable(Ptr> endpoint_manager, - Ptr> client_proxy, - const string& endpoint_id) - : endpoint_manager_(endpoint_manager), - client_proxy_(client_proxy), - endpoint_id_(endpoint_id) {} - - void run() override { - endpoint_manager_->removeEndpoint( - client_proxy_, endpoint_id_, - /*send_disconnection_notification=*/ - client_proxy_->isConnectedToEndpoint(endpoint_id_)); - } - - private: - Ptr> endpoint_manager_; - Ptr> client_proxy_; - const string endpoint_id_; -}; - -template -class GetOfflineFrameProcessorCallable - : public Callable::IncomingOfflineFrameProcessor>> { - public: - typedef Ptr::IncomingOfflineFrameProcessor> - ReturnType; - - GetOfflineFrameProcessorCallable( - Ptr> endpoint_manager, - V1Frame::FrameType frame_type) - : endpoint_manager_(endpoint_manager), frame_type_(frame_type) {} - - ExceptionOr call() override { - typename EndpointManager< - Platform>::IncomingOfflineFrameProcessorsMap::iterator it = - endpoint_manager_->incoming_offline_frame_processors_.find(frame_type_); - if (it == endpoint_manager_->incoming_offline_frame_processors_.end()) { - return ExceptionOr(ReturnType()); - } - return ExceptionOr(it->second); - } - - private: - Ptr> endpoint_manager_; - const V1Frame::FrameType frame_type_; -}; - -} // namespace endpoint_manager - -template -bool EndpointManager::IncomingOfflineFrameProcessor::operator==( - const EndpointManager::IncomingOfflineFrameProcessor& rhs) { - // We're comparing addresses because these objects are callbacks which need to - // be matched by exact instances. - return this == &rhs; + // It's now time to let the client know of this new connection so that + // they can accept or reject it. + client->OnConnectionInitiated(endpoint_id, info, options, listener); + latch.CountDown(); + }); + latch.Await(); } -template -bool EndpointManager::IncomingOfflineFrameProcessor::operator<( - const EndpointManager::IncomingOfflineFrameProcessor& rhs) { - // We're comparing addresses because these objects are callbacks which need to - // be matched by exact instances. - return this < &rhs; +void EndpointManager::UnregisterEndpoint(ClientProxy* client, + const std::string& endpoint_id) { + CountDownLatch latch(1); + RunOnEndpointManagerThread([this, client, endpoint_id, &latch]() { + RemoveEndpoint(client, endpoint_id, + client->IsConnectedToEndpoint(endpoint_id)); + latch.CountDown(); + }); + latch.Await(); } -template -const std::int32_t EndpointManager::kKeepAliveWriteIntervalMillis = - 5000; -template -const std::int32_t EndpointManager::kKeepAliveReadTimeoutMillis = - 30000; -template -const std::int32_t - EndpointManager::kProcessEndpointDisconnectionTimeoutMillis = - 2000; -template -const std::int32_t EndpointManager::kMaxConcurrentEndpoints = 50; - -template -EndpointManager::EndpointManager( - Ptr endpoint_channel_manager) - : thread_utils_(Platform::createThreadUtils()), - system_clock_(Platform::createSystemClock()), - endpoint_channel_manager_(endpoint_channel_manager), - incoming_offline_frame_processors_(), - endpoint_keep_alive_manager_thread_pool_( - Platform::createMultiThreadExecutor(kMaxConcurrentEndpoints)), - endpoint_readers_thread_pool_( - Platform::createMultiThreadExecutor(kMaxConcurrentEndpoints)), - serial_executor_(Platform::createSingleThreadExecutor()) {} - -template -EndpointManager::~EndpointManager() { - // TODO(tracyzhou): Add logging. - // Stop all the ongoing Runnables (as gracefully as possible). - serial_executor_->shutdown(); - endpoint_readers_thread_pool_->shutdown(); - endpoint_keep_alive_manager_thread_pool_->shutdown(); - - // 'incoming_offline_frame_processors' does not own the processors. - incoming_offline_frame_processors_.clear(); - // TODO(tracyzhou): Add logging. +// Designed to run asynchronously. It is called from IO thread pools, and +// jobs in these pools may be waited for from the EndpointManager thread. If we +// allow synchronous behavior here it will cause a live lock. +void EndpointManager::DiscardEndpoint(ClientProxy* client, + const std::string& endpoint_id) { + RunOnEndpointManagerThread([this, client, endpoint_id]() { + RemoveEndpoint(client, endpoint_id, + /*notify=*/ + client->IsConnectedToEndpoint(endpoint_id)); + }); } -template -void EndpointManager::registerIncomingOfflineFrameProcessor( - V1Frame::FrameType frame_type, - Ptr::IncomingOfflineFrameProcessor> - processor) { - runOnEndpointManagerThread(MakePtr( - new endpoint_manager::RegisterIncomingOfflineFrameProcessorRunnable< - Platform>(self_, frame_type, processor))); -} - -template -void EndpointManager::unregisterIncomingOfflineFrameProcessor( - V1Frame::FrameType frame_type, - Ptr::IncomingOfflineFrameProcessor> - processor) { - runOnEndpointManagerThread(MakePtr( - new endpoint_manager::UnregisterIncomingOfflineFrameProcessorRunnable< - Platform>(self_, frame_type, processor))); -} - -template -Ptr::IncomingOfflineFrameProcessor> -EndpointManager::getOfflineFrameProcessor( - V1Frame::FrameType frame_type) { - typedef Ptr::IncomingOfflineFrameProcessor> - PtrIncomingOfflineFrameProcessor; - typedef Ptr> ResultType; - - ScopedPtr future_result( - runOnEndpointManagerThread(MakePtr( - new endpoint_manager::GetOfflineFrameProcessorCallable( - self_, frame_type)))); - - return waitForResult("getOfflineFrameProcessor", future_result.get()); -} - -template -void EndpointManager::registerEndpoint( - Ptr> client_proxy, const string& endpoint_id, - const string& endpoint_name, const string& authentication_token, - ConstPtr raw_authentication_token, bool is_incoming, - Ptr endpoint_channel, - Ptr connection_lifecycle_listener) { - ScopedPtr> latch(Platform::createCountDownLatch(1)); - runOnEndpointManagerThread( - MakePtr(new endpoint_manager::RegisterEndpointRunnable( - self_, client_proxy, endpoint_id, endpoint_name, - authentication_token, raw_authentication_token, is_incoming, - endpoint_channel, connection_lifecycle_listener, latch.get()))); - waitForLatch("registerEndpoint", latch.get()); -} - -template -void EndpointManager::unregisterEndpoint( - Ptr> client_proxy, const string& endpoint_id) { - ScopedPtr> latch(Platform::createCountDownLatch(1)); - runOnEndpointManagerThread( - MakePtr(new endpoint_manager::UnregisterEndpointRunnable( - self_, client_proxy, endpoint_id, latch.get()))); - waitForLatch("unregisterEndpoint", latch.get()); -} - -template -void EndpointManager::discardEndpoint( - Ptr> client_proxy, const string& endpoint_id) { - runOnEndpointManagerThread( - MakePtr(new endpoint_manager::DiscardEndpointRunnable( - self_, client_proxy, endpoint_id))); -} - -template -std::vector EndpointManager::sendPayloadChunk( +std::vector EndpointManager::SendPayloadChunk( const PayloadTransferFrame::PayloadHeader& payload_header, const PayloadTransferFrame::PayloadChunk& payload_chunk, - const std::vector& endpoint_ids) { - ConstPtr payload_transfer_frame_bytes = - OfflineFrames::forDataPayloadTransferFrame(payload_header, payload_chunk); + const std::vector& endpoint_ids) { + ByteArray bytes = + parser::ForDataPayloadTransfer(payload_header, payload_chunk); - return sendTransferFrameBytes(endpoint_ids, payload_transfer_frame_bytes, - payload_header.id(), + return SendTransferFrameBytes(endpoint_ids, bytes, payload_header.id(), /*offset=*/payload_chunk.offset(), /*packet_type=*/"DATA"); } -template -void EndpointManager::sendControlMessage( - const PayloadTransferFrame::PayloadHeader& payload_header, - const PayloadTransferFrame::ControlMessage& control_message, - const std::vector& endpoint_ids) { - ConstPtr payload_transfer_frame_bytes = - OfflineFrames::forControlPayloadTransferFrame(payload_header, - control_message); +std::vector EndpointManager::SendControlMessage( + const PayloadTransferFrame::PayloadHeader& header, + const PayloadTransferFrame::ControlMessage& control, + const std::vector& endpoint_ids) { + ByteArray bytes = parser::ForControlPayloadTransfer(header, control); - sendTransferFrameBytes(endpoint_ids, payload_transfer_frame_bytes, - payload_header.id(), - /*offset=*/control_message.offset(), - /*packet_type=*/"CONTROL"); -} - -template -void EndpointManager::waitForLatch(const string& method_name, - Ptr latch) { - Exception::Value await_exception = latch->await(); - if (Exception::NONE != await_exception) { - if (Exception::INTERRUPTED == await_exception) { - // TODO(tracyzhou): Add logging. - // Thread.currentThread().interrupt(); - } - } -} - -template -void EndpointManager::waitForLatch(const string& method_name, - Ptr latch, - std::int32_t timeout_millis) { - ExceptionOr await_succeeded = latch->await(timeout_millis); - - if (!await_succeeded.ok()) { - // TODO(tracyzhou): Add logging. - if (Exception::INTERRUPTED == await_succeeded.exception()) { - // TODO(tracyzhou): Add logging. - // Thread.currentThread().interrupt(); - return; - } - } - - if (!await_succeeded.result()) { - // TODO(tracyzhou): Add logging. - } -} - -template -template -T EndpointManager::waitForResult(const string& method_name, - Ptr> result_future) { - ExceptionOr result = result_future->get(); - - if (!result.ok()) { - Exception::Value exception = result.exception(); - if (Exception::INTERRUPTED == exception || - Exception::EXECUTION == exception) { - // TODO(tracyzhou): Add logging. - if (Exception::INTERRUPTED == exception) { - // Thread.currentThread().interrupt(); - } - return T(); - } - } - - return result.result(); + return SendTransferFrameBytes(endpoint_ids, bytes, header.id(), + /*offset=*/control.offset(), + /*packet_type=*/"CONTROL"); } // @EndpointManagerThread -template -void EndpointManager::removeEndpoint( - Ptr> client_proxy, const string& endpoint_id, - bool send_disconnection_notification) { - // Unregistering from endpoint_channel_manager_ will also serve to terminate - // the dedicated reader and KeepAlive threads we started when we registered +void EndpointManager::RemoveEndpoint(ClientProxy* client, + const std::string& endpoint_id, + bool notify) { + // Unregistering from channel_manager_ will also serve to terminate + // the dedicated handler and KeepAlive threads we started when we registered // this endpoint. - if (endpoint_channel_manager_->unregisterChannelForEndpoint(endpoint_id)) { + if (channel_manager_->UnregisterChannelForEndpoint(endpoint_id)) { // Notify all frame processors of the disconnection immediately and wait // for them to clean up state. Only once all processors are done cleaning // up, we can remove the endpoint from ClientProxy after which there // should be no further interactions with the endpoint. // (See b/37352254 for history) - waitForEndpointDisconnectionProcessing(client_proxy, endpoint_id); + WaitForEndpointDisconnectionProcessing(client, endpoint_id); - client_proxy->onDisconnected(endpoint_id, send_disconnection_notification); - // TODO(tracyzhou): Add logging. + client->OnDisconnected(endpoint_id, notify); + NEARBY_LOG(INFO, "Removed endpoint; id=%s", endpoint_id.c_str()); } } // @EndpointManagerThread -template -void EndpointManager::waitForEndpointDisconnectionProcessing( - Ptr> client_proxy, const string& endpoint_id) { - ScopedPtr> process_disconnection_barrier( - Platform::createCountDownLatch(static_cast( - incoming_offline_frame_processors_.size()))); +void EndpointManager::WaitForEndpointDisconnectionProcessing( + ClientProxy* client, const std::string& endpoint_id) { + NEARBY_LOGS(INFO) << "Wait: client=" << client << "; id=" << endpoint_id; + auto total_size = frame_processors_.size(); + NEARBY_LOGS(INFO) << "Total frame processors: " << total_size; + if (!total_size) return; + CountDownLatch barrier(total_size); - for (typename IncomingOfflineFrameProcessorsMap::iterator it = - incoming_offline_frame_processors_.begin(); - it != incoming_offline_frame_processors_.end(); it++) { - it->second->processEndpointDisconnection( - client_proxy, endpoint_id, process_disconnection_barrier.get()); + int valid = 0; + for (auto& item : frame_processors_) { + auto* processor = item.second; + NEARBY_LOGS(INFO) << "processor=" << processor << "; type=" << item.first; + if (processor) { + valid++; + processor->OnEndpointDisconnect(client, endpoint_id, &barrier); + } else { + barrier.CountDown(); + } } - waitForLatch("waitForEndpointDisconnectionProcessing", - process_disconnection_barrier.get(), - kProcessEndpointDisconnectionTimeoutMillis); + if (!valid) { + NEARBY_LOGS(INFO) << "No valid frame processors."; + return; + } else { + NEARBY_LOGS(INFO) << "Valid frame processors: " << valid; + } + + NEARBY_LOGS(INFO) << "Waiting for " << valid + << " frame processors to disconnect from: " << endpoint_id; + if (!barrier.Await(kProcessEndpointDisconnectionTimeout).result()) { + NEARBY_LOGS(INFO) << "Failed to disconnect frame processors from: " + << endpoint_id; + } else { + NEARBY_LOGS(INFO) + << "Finished waiting for frame processors to disconnect from: " + << endpoint_id; + } } -template -std::vector EndpointManager::sendTransferFrameBytes( - const std::vector& endpoint_ids, - ConstPtr payload_transfer_frame_bytes, std::int64_t payload_id, - std::int64_t offset, const string& packet_type) { - ScopedPtr> scoped_payload_transfer_frame_bytes( - payload_transfer_frame_bytes); - std::vector failed_endpoint_ids; - for (std::vector::const_iterator it = endpoint_ids.begin(); - it != endpoint_ids.end(); it++) { - const string& endpoint_id = *it; +std::vector EndpointManager::SendTransferFrameBytes( + const std::vector& endpoint_ids, const ByteArray& bytes, + std::int64_t payload_id, std::int64_t offset, + const std::string& packet_type) { + std::vector failed_endpoint_ids; + for (const std::string& endpoint_id : endpoint_ids) { + std::shared_ptr channel = + channel_manager_->GetChannelForEndpoint(endpoint_id); - ScopedPtr> scoped_endpoint_channel( - endpoint_channel_manager_->getChannelForEndpoint(endpoint_id)); - - if (scoped_endpoint_channel.isNull()) { + if (channel == nullptr) { // We no longer know about this endpoint (it was either explicitly // unregistered, or a read/write error made us unregister it internally). - // TODO(tracyzhou): Add logging. + NEARBY_LOG(INFO, "Channel not available; id=%s", endpoint_id.c_str()); failed_endpoint_ids.push_back(endpoint_id); continue; } - Exception::Value write_exception = scoped_endpoint_channel->write( - scoped_payload_transfer_frame_bytes.release()); - if (Exception::NONE != write_exception) { - if (Exception::IO == write_exception) { - // TODO(tracyzhou): Add logging. - failed_endpoint_ids.push_back(endpoint_id); - continue; - } + Exception write_exception = channel->Write(bytes); + if (!write_exception.Ok()) { + failed_endpoint_ids.push_back(endpoint_id); + NEARBY_LOG(INFO, "Failed to send packet; endpoint_id=%s", + endpoint_id.c_str()); + continue; } } return failed_endpoint_ids; } -template -void EndpointManager::startEndpointReader(Ptr runnable) { - endpoint_readers_thread_pool_->execute(runnable); +void EndpointManager::StartEndpointReader(Runnable runnable) { + handlers_executor_.Execute(std::move(runnable)); } -template -void EndpointManager::startEndpointKeepAliveManager( - Ptr runnable) { - endpoint_keep_alive_manager_thread_pool_->execute(runnable); +void EndpointManager::StartEndpointKeepAliveManager(Runnable runnable) { + keep_alive_executor_.Execute(std::move(runnable)); } -template -void EndpointManager::runOnEndpointManagerThread( - Ptr runnable) { - serial_executor_->execute(runnable); -} - -template -template -Ptr> EndpointManager::runOnEndpointManagerThread( - Ptr> callable) { - return serial_executor_->submit(callable); +void EndpointManager::RunOnEndpointManagerThread(Runnable runnable) { + serial_executor_.Execute(std::move(runnable)); } } // namespace connections diff --git a/cpp/core/internal/endpoint_manager.h b/cpp/core/internal/endpoint_manager.h index 7fd5b5df..bd40159d 100644 --- a/cpp/core/internal/endpoint_manager.h +++ b/cpp/core/internal/endpoint_manager.h @@ -7,118 +7,109 @@ #include "core/internal/client_proxy.h" #include "core/internal/endpoint_channel.h" #include "core/internal/endpoint_channel_manager.h" +#include "core/listeners.h" #include "proto/connections/offline_wire_formats.pb.h" -#include "platform/api/count_down_latch.h" -#include "platform/api/submittable_executor.h" -#include "platform/api/system_clock.h" -#include "platform/api/thread_utils.h" -#include "platform/byte_array.h" -#include "platform/port/string.h" -#include "platform/ptr.h" -#include "platform/runnable.h" +#include "platform/base/byte_array.h" +#include "platform/base/runnable.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/multi_thread_executor.h" +#include "platform/public/single_thread_executor.h" +#include "platform/public/system_clock.h" #include "proto/connections_enums.pb.h" +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" +#include "absl/time/time.h" namespace location { namespace nearby { namespace connections { -namespace endpoint_manager { - -template -class ReaderRunnable; -template -class KeepAliveManagerRunnable; -template -class EndpointChannelLoopRunnable; -template -class RegisterIncomingOfflineFrameProcessorRunnable; -template -class UnregisterIncomingOfflineFrameProcessorRunnable; -template -class RegisterEndpointRunnable; -template -class UnregisterEndpointRunnable; -template -class DiscardEndpointRunnable; -template -class GetOfflineFrameProcessorCallable; - -} // namespace endpoint_manager - // Manages all operations related to the remote endpoints with which we are // interacting. // -//

All processing of incoming and outgoing payloads is spread across this and +// All processing of incoming and outgoing payloads is spread across this and // the PayloadManager as described below. // -//

The sending of outgoing payloads originates in -// PayloadManager.sendPayload() before control is transferred over to -// EndpointManager.sendPayloadChunk(). This work happens on one of three +// The sending of outgoing payloads originates in +// PayloadManager::SendPayload() before control is transferred over to +// EndpointManager::SendPayloadChunk(). This work happens on one of three // dedicated writer threads belonging to the PayloadManager. The writer thread -// that is used depends on the PayloadType. +// that is used depends on the Payload::Type. // -//

The EndpointManager has one dedicated reader thread for each registered +// The EndpointManager has one dedicated reader thread for each registered // endpoint, and the receiving of every incoming payload (and its subsequent // chunks) originates on one of those threads before control is transferred over -// to PayloadManager.processIncomingOfflineFrame() (still running on that +// to PayloadManager::ProcessFrame() (still running on that // same dedicated reader thread). -template + class EndpointManager { public: - class IncomingOfflineFrameProcessor { + class FrameProcessor { public: - virtual ~IncomingOfflineFrameProcessor() {} + using Handle = void*; + + virtual ~FrameProcessor() = default; - // This function takes full ownership of offline_frame. // @EndpointManagerReaderThread - virtual void processIncomingOfflineFrame( - ConstPtr offline_frame, const string& from_endpoint_id, - Ptr > to_client_proxy, - proto::connections::Medium current_medium) = 0; + // Called for every incoming frame of registered type. + // NOTE(OfflineFrame& frame): + // For large payload in data phase, resources may be saved if data is moved, + // rather than copied (if passing data by reference is not an option). + // To achieve that, OfflineFrame needs to be either mutabe lvalue reference, + // or rvalue reference. Rvalue references are discouraged by go/cstyle, + // and that leaves us with mutable lvalue reference. + virtual void OnIncomingFrame(OfflineFrame& offline_frame, + const std::string& from_endpoint_id, + ClientProxy* to_client, + proto::connections::Medium current_medium) = 0; - // Implementations must call process_disconnection_barrier.countDown() once + // Implementations must call barrier.CountDown() once // they're done. This parallelizes the disconnection event across all frame // processors. // // @EndpointManagerThread - virtual void processEndpointDisconnection( - Ptr > client_proxy, const string& endpoint_id, - Ptr process_disconnection_barrier) = 0; - - // Operator overloads when comparing Ptr. - bool operator==( - const typename EndpointManager::IncomingOfflineFrameProcessor& - rhs); - bool operator<( - const typename EndpointManager::IncomingOfflineFrameProcessor& - rhs); + virtual void OnEndpointDisconnect(ClientProxy* client, + const std::string& endpoint_id, + CountDownLatch* barrier) = 0; }; - explicit EndpointManager( - Ptr endpoint_channel_manager); + explicit EndpointManager(EndpointChannelManager* manager); ~EndpointManager(); // Invoked from the constructors of the various *Manager components that make // up the OfflineServiceController implementation. - void registerIncomingOfflineFrameProcessor( - V1Frame::FrameType frame_type, - Ptr processor); - void unregisterIncomingOfflineFrameProcessor( - V1Frame::FrameType frame_type, - Ptr processor); + // FrameProcessor* instances are of dynamic duration and survive all sessions. + // returns unique handle to be used for unregistering. + // Blocks until registration is complete. + FrameProcessor::Handle RegisterFrameProcessor(V1Frame::FrameType frame_type, + FrameProcessor* processor); + void UnregisterFrameProcessor(V1Frame::FrameType frame_type, + const void* handle, bool sync = false); - // Invoked from the different PCPHandler implementations (of which there can + // Invoked from the different PcpHandler implementations (of which there can // be only one at a time). - void registerEndpoint( - Ptr > client_proxy, const string& endpoint_id, - const string& endpoint_name, const string& authentication_token, - ConstPtr raw_authentication_token, bool is_incoming, - Ptr endpoint_channel, - Ptr connection_lifecycle_listener); + // Blocks until registration is complete. + void RegisterEndpoint(ClientProxy* client, const std::string& endpoint_id, + const ConnectionResponseInfo& info, + const ConnectionOptions& options, + std::unique_ptr channel, + const ConnectionListener& listener); // Called when a client explicitly asks to disconnect from this endpoint. In // this case, we do not notify the client of onDisconnected(). - void unregisterEndpoint(Ptr > client_proxy, - const string& endpoint_id); + void UnregisterEndpoint(ClientProxy* client, const std::string& endpoint_id); + + // Returns the list of endpoints to which sending this chunk failed. + // + // Invoked from the PayloadManager's sendPayload() method. + std::vector SendPayloadChunk( + const PayloadTransferFrame::PayloadHeader& payload_header, + const PayloadTransferFrame::PayloadChunk& payload_chunk, + const std::vector& endpoint_ids); + std::vector SendControlMessage( + const PayloadTransferFrame::PayloadHeader& payload_header, + const PayloadTransferFrame::ControlMessage& control_message, + const std::vector& endpoint_ids); + // Called when we internally want to get rid of the endpoint, without the // client directly telling us to. For example... // a) We failed to read from the endpoint in its dedicated reader thread. @@ -129,106 +120,106 @@ class EndpointManager { // believe the endpoint is in a healthy state. // // Note: This must not block. Otherwise we can get into a deadlock where we - // ask everyone who's registered an IncomingOfflineFrameProcessor to - // processEndpointDisconnection() while the caller of discardEndpoint() is + // ask everyone who's registered an FrameProcessor to + // processEndpointDisconnection() while the caller of DiscardEndpoint() is // blocked here. - void discardEndpoint(Ptr > client_proxy, - const string& endpoint_id); - - Ptr getOfflineFrameProcessor( - V1Frame::FrameType frame_type); - - // Returns the list of endpoints to which sending this chunk failed. - // - // Invoked from the PayloadManager's sendPayload() method. - std::vector sendPayloadChunk( - const PayloadTransferFrame::PayloadHeader& payload_header, - const PayloadTransferFrame::PayloadChunk& payload_chunk, - const std::vector& endpoint_ids); - void sendControlMessage( - const PayloadTransferFrame::PayloadHeader& payload_header, - const PayloadTransferFrame::ControlMessage& control_message, - const std::vector& endpoint_ids); + void DiscardEndpoint(ClientProxy* client, const std::string& endpoint_id); private: - template - friend class endpoint_manager::ReaderRunnable; - template - friend class endpoint_manager::KeepAliveManagerRunnable; - template - friend class endpoint_manager::EndpointChannelLoopRunnable; - template - friend class endpoint_manager::RegisterIncomingOfflineFrameProcessorRunnable; - template - friend class endpoint_manager:: - UnregisterIncomingOfflineFrameProcessorRunnable; - template - friend class endpoint_manager::RegisterEndpointRunnable; - template - friend class endpoint_manager::UnregisterEndpointRunnable; - template - friend class endpoint_manager::DiscardEndpointRunnable; - template - friend class endpoint_manager::GetOfflineFrameProcessorCallable; + struct EndpointState { + // ClientProxy object associated with this endpoint. + ClientProxy* client; + // Execution barrier, used to ensure that all workers associated with an + // endpoint on handlers_executor_ and keep_alive_executor_ are terminated. + CountDownLatch barrier{2}; + }; - static void waitForLatch(const string& method_name, - Ptr latch); - static void waitForLatch(const string& method_name, Ptr latch, - std::int32_t timeout_millis); - template - static T waitForResult(const string& method_name, - Ptr > result_future); + FrameProcessor* GetFrameProcessor(V1Frame::FrameType frame_type); - static const std::int32_t kKeepAliveWriteIntervalMillis; - static const std::int32_t kKeepAliveReadTimeoutMillis; - static const std::int32_t kProcessEndpointDisconnectionTimeoutMillis; - static const std::int32_t kMaxConcurrentEndpoints; - static const std::int32_t kEndpointIdLength; + ExceptionOr HandleData(const std::string& endpoint_id, + ClientProxy* client_proxy, + EndpointChannel* endpoint_channel); + + ExceptionOr HandleKeepAlive(EndpointChannel* endpoint_channel); + + // Waits for a given endpoint EndpointChannelLoopRunnable() workers to + // terminate. + // Is called from RegisterEndpoint to avoid races; also called from + // RemoveEndpoint as part of proper endpoint shutdown sequence. + // @EndpointManagerThread + void EnsureWorkersTerminated(const std::string& endpoint_id); + + void EndpointChannelLoopRunnable( + const std::string& runnable_name, ClientProxy* client_proxy, + const std::string& endpoint_id, CountDownLatch* barrier, + std::function(EndpointChannel*)> handler); + + static void WaitForLatch(const std::string& method_name, + CountDownLatch* latch); + static void WaitForLatch(const std::string& method_name, + CountDownLatch* latch, std::int32_t timeout_millis); + + static constexpr absl::Duration kKeepAliveWriteInterval = + absl::Milliseconds(5000); + static constexpr absl::Duration kKeepAliveReadTimeout = + absl::Milliseconds(30000); + static constexpr absl::Duration kProcessEndpointDisconnectionTimeout = + absl::Milliseconds(2000); + static constexpr std::int32_t kMaxConcurrentEndpoints = 50; + static constexpr absl::Time kInvalidTimestamp = absl::InfinitePast(); // It should be noted that this method may be called multiple times (because // invoking this method closes the endpoint channel, which causes the // dedicated reader and KeepAlive threads to terminate, which in turn leads to // this method being called), but that's alright because the implementation of // this method is idempotent. - void removeEndpoint(Ptr > client_proxy, - const string& endpoint_id, - bool send_disconnection_notification); + // @EndpointManagerThread + void RemoveEndpoint(ClientProxy* client, const std::string& endpoint_id, + bool notify); - void waitForEndpointDisconnectionProcessing( - Ptr > client_proxy, const string& endpoint_id); + void WaitForEndpointDisconnectionProcessing(ClientProxy* client, + const std::string& endpoint_id); - std::vector sendTransferFrameBytes( - const std::vector& endpoint_ids, - ConstPtr payload_transfer_frame_bytes, std::int64_t payload_id, - std::int64_t offset, const string& packet_type); + std::vector SendTransferFrameBytes( + const std::vector& endpoint_ids, + const ByteArray& payload_transfer_frame_bytes, std::int64_t payload_id, + std::int64_t offset, const std::string& packet_type); - void startEndpointReader(Ptr runnable); - void startEndpointKeepAliveManager(Ptr runnable); - void runOnEndpointManagerThread(Ptr runnable); - template - Ptr > runOnEndpointManagerThread(Ptr > callable); + // Executes data-handing jobs on a separate thread for each endpoint, on a + // handlers_executor_. + // If amount of concurrent connections is less the pool capacity, it is + // possible that while a channel is being replaced, two jobs are trying to + // run for the same endpoint (for a short time). + // TODO (apolyudov): do not let extra job start. + void StartEndpointReader(Runnable runnable); - ScopedPtr > thread_utils_; - ScopedPtr > system_clock_; + // Executes keep-alive jobs on a separate thread for each endpoint on a + // keep_alive_executor_. + void StartEndpointKeepAliveManager(Runnable runnable); - Ptr endpoint_channel_manager_; + // Executes all jobs sequentially, on a serial_executor_. + void RunOnEndpointManagerThread(Runnable runnable); - typedef std::map > - IncomingOfflineFrameProcessorsMap; - IncomingOfflineFrameProcessorsMap incoming_offline_frame_processors_; + EndpointChannelManager* channel_manager_; - ScopedPtr > - endpoint_keep_alive_manager_thread_pool_; - ScopedPtr > - endpoint_readers_thread_pool_; - ScopedPtr > serial_executor_; - std::shared_ptr> self_{this, [](void*){}}; + absl::flat_hash_map frame_processors_; + + // We keep track of all registered channel endpoints here. + absl::flat_hash_map endpoints_; + + MultiThreadExecutor keep_alive_executor_{kMaxConcurrentEndpoints}; + MultiThreadExecutor handlers_executor_{kMaxConcurrentEndpoints}; + SingleThreadExecutor serial_executor_; }; +// Operator overloads when comparing FrameProcessor*. +bool operator==(const EndpointManager::FrameProcessor& lhs, + const EndpointManager::FrameProcessor& rhs); +bool operator<(const EndpointManager::FrameProcessor& lhs, + const EndpointManager::FrameProcessor& rhs); + } // namespace connections } // namespace nearby } // namespace location -#include "core/internal/endpoint_manager.cc" - #endif // CORE_INTERNAL_ENDPOINT_MANAGER_H_ diff --git a/cpp/core_v2/internal/endpoint_manager_test.cc b/cpp/core/internal/endpoint_manager_test.cc similarity index 95% rename from cpp/core_v2/internal/endpoint_manager_test.cc rename to cpp/core/internal/endpoint_manager_test.cc index 7842454e..f29f4e99 100644 --- a/cpp/core_v2/internal/endpoint_manager_test.cc +++ b/cpp/core/internal/endpoint_manager_test.cc @@ -1,17 +1,17 @@ -#include "core_v2/internal/endpoint_manager.h" +#include "core/internal/endpoint_manager.h" #include #include -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/endpoint_channel_manager.h" -#include "core_v2/internal/offline_frames.h" -#include "core_v2/options.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/exception.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/logging.h" -#include "platform_v2/public/pipe.h" +#include "core/internal/client_proxy.h" +#include "core/internal/endpoint_channel_manager.h" +#include "core/internal/offline_frames.h" +#include "core/options.h" +#include "platform/base/byte_array.h" +#include "platform/base/exception.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/logging.h" +#include "platform/public/pipe.h" #include "proto/connections_enums.pb.h" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/cpp/core/internal/internal_payload.cc b/cpp/core/internal/internal_payload.cc index ca485783..c9591b42 100644 --- a/cpp/core/internal/internal_payload.cc +++ b/cpp/core/internal/internal_payload.cc @@ -4,16 +4,14 @@ namespace location { namespace nearby { namespace connections { -InternalPayload::InternalPayload(ConstPtr payload) - : payload_(payload), payload_id_(payload_->getId()) {} +InternalPayload::InternalPayload(Payload payload) + : payload_(std::move(payload)), payload_id_(payload_.GetId()) {} -InternalPayload::~InternalPayload() {} - -ConstPtr InternalPayload::releasePayload() { - return payload_.release(); +Payload InternalPayload::ReleasePayload() { + return std::move(payload_); } -std::int64_t InternalPayload::getId() const { return payload_id_; } +Payload::Id InternalPayload::GetId() const { return payload_id_; } } // namespace connections } // namespace nearby diff --git a/cpp/core/internal/internal_payload.h b/cpp/core/internal/internal_payload.h index 33f11860..e08b8074 100644 --- a/cpp/core/internal/internal_payload.h +++ b/cpp/core/internal/internal_payload.h @@ -5,9 +5,8 @@ #include "core/payload.h" #include "proto/connections/offline_wire_formats.pb.h" -#include "platform/byte_array.h" -#include "platform/exception.h" -#include "platform/ptr.h" +#include "platform/base/byte_array.h" +#include "platform/base/exception.h" namespace location { namespace nearby { @@ -20,12 +19,12 @@ namespace connections { // Payload. class InternalPayload { public: - explicit InternalPayload(ConstPtr payload); - virtual ~InternalPayload(); + explicit InternalPayload(Payload payload); + virtual ~InternalPayload() = default; - ConstPtr releasePayload(); + Payload ReleasePayload(); - std::int64_t getId() const; + Payload::Id GetId() const; // Returns the PayloadType of the Payload to which this object is bound. // @@ -34,13 +33,13 @@ class InternalPayload { // Payload::getType(). // // @return The PayloadType. - virtual PayloadTransferFrame::PayloadHeader::PayloadType getType() const = 0; + virtual PayloadTransferFrame::PayloadHeader::PayloadType GetType() const = 0; // Deduces the total size of the Payload to which this object is bound. // // @return The total size, or -1 if it cannot be deduced (for example, when // dealing with streaming data). - virtual std::int64_t getTotalSize() const = 0; + virtual std::int64_t GetTotalSize() const = 0; // Breaks off the next chunk from the Payload to which this object is bound. // @@ -49,7 +48,7 @@ class InternalPayload { // a Binder, or another device altogether). // // @return The next chunk from the Payload, or null if we've reached the end. - virtual ExceptionOr > detachNextChunk() = 0; + virtual ByteArray DetachNextChunk() = 0; // Adds the next chunk that comprises the Payload to which this object is // bound. @@ -61,18 +60,18 @@ class InternalPayload { // @param chunk The next chunk; this being null signals that this is the last // chunk, which will typically be used as a trigger to perform whatever state // cleanup may be required by the concrete implementation. - virtual Exception::Value attachNextChunk(ConstPtr chunk) = 0; + virtual Exception AttachNextChunk(const ByteArray& chunk) = 0; // Cleans up any resources used by this Payload. Called when we're stopping // early, e.g. after being cancelled or having no more recipients left. - virtual void close() {} + virtual void Close() {} protected: - ScopedPtr > payload_; + Payload payload_; // We're caching the payload ID here because the backing payload will be // released to another owner during the lifetime of an incoming // InternalPayload. - const std::int64_t payload_id_; + Payload::Id payload_id_; }; } // namespace connections diff --git a/cpp/core/internal/internal_payload_factory.cc b/cpp/core/internal/internal_payload_factory.cc index dd5c6cdb..6cbf4da3 100644 --- a/cpp/core/internal/internal_payload_factory.cc +++ b/cpp/core/internal/internal_payload_factory.cc @@ -1,15 +1,16 @@ #include "core/internal/internal_payload_factory.h" #include +#include #include "core/payload.h" -#include "platform/api/condition_variable.h" -#include "platform/api/input_file.h" -#include "platform/api/lock.h" -#include "platform/api/output_file.h" -#include "platform/byte_array.h" -#include "platform/exception.h" -#include "platform/pipe.h" +#include "platform/base/byte_array.h" +#include "platform/base/exception.h" +#include "platform/public/condition_variable.h" +#include "platform/public/file.h" +#include "platform/public/mutex.h" +#include "platform/public/pipe.h" +#include "absl/memory/memory.h" namespace location { namespace nearby { @@ -19,291 +20,258 @@ namespace { class BytesInternalPayload : public InternalPayload { public: - explicit BytesInternalPayload(ConstPtr payload) - : InternalPayload(payload), - total_size_(payload_->asBytes()->size()), + explicit BytesInternalPayload(Payload payload) + : InternalPayload(std::move(payload)), + total_size_(payload_.AsBytes().size()), detached_only_chunk_(false) {} - PayloadTransferFrame::PayloadHeader::PayloadType getType() const override { + PayloadTransferFrame::PayloadHeader::PayloadType GetType() const override { return PayloadTransferFrame::PayloadHeader::BYTES; } - std::int64_t getTotalSize() const override { return total_size_; } + std::int64_t GetTotalSize() const override { return total_size_; } - ExceptionOr > detachNextChunk() override { + // Relinquishes ownership of the payload_; retrieves and returns the stored + // ByteArray. + ByteArray DetachNextChunk() override { if (detached_only_chunk_) { - return ExceptionOr >(ConstPtr()); + return {}; } detached_only_chunk_ = true; - return ExceptionOr >(payload_->releaseBytes()); + return std::move(payload_).AsBytes(); } - Exception::Value attachNextChunk(ConstPtr chunk) override { - // Avoid leaks. - ScopedPtr > scoped_chunk(chunk); - - // Nothing to do - this method makes sense for other, more long-running - // InternalPayload concrete implementations. - return Exception::NONE; + // Does nothing. + Exception AttachNextChunk(const ByteArray& chunk) override { + return {Exception::kSuccess}; } private: // We're caching the total size here because the backing payload will be - // released to another owner during the lifetime of an incoming + // moved to another owner during the lifetime of an incoming // InternalPayload. const std::int64_t total_size_; bool detached_only_chunk_; }; -template class OutgoingStreamInternalPayload : public InternalPayload { public: - explicit OutgoingStreamInternalPayload(ConstPtr payload) - : InternalPayload(payload) {} + explicit OutgoingStreamInternalPayload(Payload payload) + : InternalPayload(std::move(payload)) {} - PayloadTransferFrame::PayloadHeader::PayloadType getType() const override { + PayloadTransferFrame::PayloadHeader::PayloadType GetType() const override { return PayloadTransferFrame::PayloadHeader::STREAM; } - std::int64_t getTotalSize() const override { return -1; } + std::int64_t GetTotalSize() const override { return -1; } - ExceptionOr > detachNextChunk() override { - Ptr input_stream(payload_->asStream()->asInputStream()); + ByteArray DetachNextChunk() override { + InputStream* input_stream = payload_.AsStream(); + if (!input_stream) return {}; - ExceptionOr > bytes_read = - input_stream->read(kChunkSize); + ExceptionOr bytes_read = input_stream->Read(kChunkSize); if (!bytes_read.ok()) { - if (Exception::IO == bytes_read.exception()) { - // Ignore the potential Exception returned by close(), as a counterpart - // to Java's closeQuietly(). - input_stream->close(); - return bytes_read; - } + input_stream->Close(); + return {}; } - // Avoid leaks. - ScopedPtr > scoped_bytes_read(bytes_read.result()); + ByteArray scoped_bytes_read = std::move(bytes_read.result()); - if (scoped_bytes_read.isNull()) { + if (scoped_bytes_read.Empty()) { // TODO(reznor): logger.atVerbose().log("No more data for outgoing payload // %s, closing InputStream.", this); - // Ignore the potential Exception returned by close(), as a counterpart - // to Java's closeQuietly(). - input_stream->close(); - return ExceptionOr >(ConstPtr()); + input_stream->Close(); + return {}; } - return ExceptionOr >(scoped_bytes_read.release()); + return scoped_bytes_read; } - Exception::Value attachNextChunk(ConstPtr chunk) override { - return Exception::IO; + Exception AttachNextChunk(const ByteArray& chunk) override { + return {Exception::kIo}; } - void close() override { + void Close() override { // Ignore the potential Exception returned by close(), as a counterpart // to Java's closeQuietly(). - payload_->asStream()->asInputStream()->close(); + InputStream* stream = payload_.AsStream(); + if (stream) stream->Close(); } private: - static constexpr std::int64_t kChunkSize = 64 * 1024; + static constexpr std::int64_t kChunkSize = Pipe::kChunkSize; }; -template class IncomingStreamInternalPayload : public InternalPayload { public: - IncomingStreamInternalPayload(ConstPtr payload, - Ptr output_stream) - : InternalPayload(payload), output_stream_(output_stream) {} + IncomingStreamInternalPayload(Payload payload, OutputStream& output_stream) + : InternalPayload(std::move(payload)), output_stream_(&output_stream) {} - PayloadTransferFrame::PayloadHeader::PayloadType getType() const override { + PayloadTransferFrame::PayloadHeader::PayloadType GetType() const override { return PayloadTransferFrame::PayloadHeader::STREAM; } - std::int64_t getTotalSize() const override { return -1; } + std::int64_t GetTotalSize() const override { return -1; } - ExceptionOr > detachNextChunk() override { - return ExceptionOr >(Exception::IO); - } + ByteArray DetachNextChunk() override { return {}; } - Exception::Value attachNextChunk(ConstPtr chunk) override { - ScopedPtr > scoped_chunk(chunk); - - if (scoped_chunk.isNull()) { - output_stream_->close(); - return Exception::NONE; + Exception AttachNextChunk(const ByteArray& chunk) override { + if (chunk.Empty()) { + output_stream_->Close(); + return {Exception::kSuccess}; } - return output_stream_->write(scoped_chunk.release()); + return output_stream_->Write(chunk); } - void close() override { - output_stream_->close(); - } + void Close() override { output_stream_->Close(); } private: - ScopedPtr > output_stream_; + OutputStream* output_stream_; }; class OutgoingFileInternalPayload : public InternalPayload { public: - explicit OutgoingFileInternalPayload(ConstPtr payload) - : InternalPayload(std::move(payload)) {} + explicit OutgoingFileInternalPayload(Payload payload) + : InternalPayload(std::move(payload)), + total_size_{payload_.AsFile()->GetTotalSize()} {} - PayloadTransferFrame::PayloadHeader::PayloadType getType() const override { + PayloadTransferFrame::PayloadHeader::PayloadType GetType() const override { return PayloadTransferFrame::PayloadHeader::FILE; } - std::int64_t getTotalSize() const override { - return payload_->asFile()->asInputFile()->getTotalSize(); - } + std::int64_t GetTotalSize() const override { return total_size_; } - ExceptionOr> detachNextChunk() override { - Ptr input_file(payload_->asFile()->asInputFile()); + ByteArray DetachNextChunk() override { + InputFile* file = payload_.AsFile(); + if (!file) return {}; - ExceptionOr> bytes_read = input_file->read(kChunkSize); + ExceptionOr bytes_read = file->Read(kChunkSize); if (!bytes_read.ok()) { - if (Exception::IO == bytes_read.exception()) { - input_file->close(); - return bytes_read; - } + return {}; } - // Avoid leaks. - ScopedPtr> scoped_bytes_read(bytes_read.result()); + ByteArray bytes = std::move(bytes_read.result()); - if (scoped_bytes_read.isNull()) { + if (bytes.Empty()) { // No more data for outgoing payload. - input_file->close(); - return ExceptionOr>(ConstPtr()); + file->Close(); + return {}; } - return ExceptionOr>(scoped_bytes_read.release()); + return bytes; } - Exception::Value attachNextChunk(ConstPtr chunk) override { - return Exception::IO; + Exception AttachNextChunk(const ByteArray& chunk) override { + return {Exception::kIo}; } - void close() override { payload_->asFile()->asInputFile()->close(); } + void Close() override { + InputFile* file = payload_.AsFile(); + if (file) file->Close(); + } private: + std::int64_t total_size_; static constexpr std::int64_t kChunkSize = 64 * 1024; }; class IncomingFileInternalPayload : public InternalPayload { public: - IncomingFileInternalPayload(ConstPtr payload, - const Ptr& output_file, + IncomingFileInternalPayload(Payload payload, OutputFile output_file, std::int64_t total_size) : InternalPayload(std::move(payload)), - output_file_(output_file), + output_file_(std::move(output_file)), total_size_(total_size) {} - PayloadTransferFrame::PayloadHeader::PayloadType getType() const override { + PayloadTransferFrame::PayloadHeader::PayloadType GetType() const override { return PayloadTransferFrame::PayloadHeader::FILE; } - std::int64_t getTotalSize() const override { return total_size_; } + std::int64_t GetTotalSize() const override { return total_size_; } - ExceptionOr> detachNextChunk() override { - return ExceptionOr>(Exception::IO); - } + ByteArray DetachNextChunk() override { return {}; } - Exception::Value attachNextChunk(ConstPtr chunk) override { - ScopedPtr> scoped_chunk(chunk); - - if (scoped_chunk.isNull()) { + Exception AttachNextChunk(const ByteArray& chunk) override { + if (chunk.Empty()) { // Received null last chunk for incoming payload. - output_file_->close(); - return Exception::NONE; + output_file_.Close(); + return {Exception::kSuccess}; } - return output_file_->write(scoped_chunk.release()); + return output_file_.Write(chunk); } - void close() override { output_file_->close(); } + void Close() override { output_file_.Close(); } private: - ScopedPtr> output_file_; + OutputFile output_file_; const std::int64_t total_size_; }; } // namespace -template -Ptr InternalPayloadFactory::createOutgoing( - ConstPtr payload) { - // Avoid leaks. - ScopedPtr > scoped_payload(payload); +std::unique_ptr CreateOutgoingInternalPayload( + Payload payload) { + switch (payload.GetType()) { + case Payload::Type::kBytes: + return absl::make_unique(std::move(payload)); - switch (scoped_payload->getType()) { - case Payload::Type::BYTES: - return MakePtr(new BytesInternalPayload(scoped_payload.release())); + case Payload::Type::kFile: { + InputFile* file = payload.AsFile(); + const PayloadId file_payload_id = file ? file->GetPayloadId() : 0; + const PayloadId payload_id = payload.GetId(); + CHECK(payload_id == file_payload_id); + return absl::make_unique(std::move(payload)); + } - case Payload::Type::FILE: - return MakePtr(new OutgoingFileInternalPayload(scoped_payload.release())); + case Payload::Type::kStream: + return absl::make_unique( + std::move(payload)); - case Payload::Type::STREAM: - return MakePtr(new OutgoingStreamInternalPayload( - scoped_payload.release())); - - default: {} - // Fall through + default: + DCHECK(false); // This should never happen. + return {}; } - - // This should never be reached since the ServiceControllerRouter has already - // checked whether or not we can work with this Payload type. - return Ptr(); } -template -Ptr InternalPayloadFactory::createIncoming( - const PayloadTransferFrame& payload_transfer_frame) { - if (PayloadTransferFrame::DATA != payload_transfer_frame.packet_type()) { - return Ptr(); +std::unique_ptr CreateIncomingInternalPayload( + const PayloadTransferFrame& frame) { + if (frame.packet_type() != PayloadTransferFrame::DATA) { + return {}; } - const int64_t payload_id = payload_transfer_frame.payload_header().id(); - switch (payload_transfer_frame.payload_header().type()) { + const Payload::Id payload_id = frame.payload_header().id(); + switch (frame.payload_header().type()) { case PayloadTransferFrame::PayloadHeader::BYTES: { - const string& body = payload_transfer_frame.payload_chunk().body(); - return MakePtr(new BytesInternalPayload(MakeConstPtr(new Payload( - payload_id, MakeConstPtr(new ByteArray(body.data(), body.size())))))); + return absl::make_unique( + Payload(payload_id, ByteArray(frame.payload_chunk().body()))); } case PayloadTransferFrame::PayloadHeader::STREAM: { - // pipe will be auto-destroyed when it is no longer referenced. - auto pipe = MakeRefCountedPtr(new Pipe()); + auto pipe = std::make_shared(); - return MakePtr(new IncomingStreamInternalPayload( - MakeConstPtr( - new Payload(payload_id, MakeConstPtr(new Payload::Stream( - Pipe::createInputStream(pipe))))), - Pipe::createOutputStream(pipe))); + return absl::make_unique( + Payload(payload_id, + [pipe]() -> InputStream& { + return pipe->GetInputStream(); // NOLINT + }), + pipe->GetOutputStream()); } case PayloadTransferFrame::PayloadHeader::FILE: { - Ptr output_file = Platform::createOutputFile(payload_id); - Ptr input_file = Platform::createInputFile( - payload_id, payload_transfer_frame.payload_header().total_size()); - ConstPtr payload = MakeConstPtr( - new Payload(payload_id, MakeConstPtr(new Payload::File(input_file)))); - return MakePtr(new IncomingFileInternalPayload( - payload, output_file, - payload_transfer_frame.payload_header().total_size())); + std::int64_t total_size = frame.payload_header().total_size(); + return absl::make_unique( + Payload(payload_id, InputFile(payload_id, total_size)), + OutputFile(payload_id), total_size); } - default: {} - // Fall through. + default: + DCHECK(false); // This should never happen. + return {}; } - - // This should never be reached since the ServiceControllerRouter has - // already checked whether or not we can work with this Payload type. - return Ptr(); } } // namespace connections diff --git a/cpp/core/internal/internal_payload_factory.h b/cpp/core/internal/internal_payload_factory.h index 0b7086e6..f5afde13 100644 --- a/cpp/core/internal/internal_payload_factory.h +++ b/cpp/core/internal/internal_payload_factory.h @@ -4,31 +4,21 @@ #include "core/internal/internal_payload.h" #include "core/payload.h" #include "proto/connections/offline_wire_formats.pb.h" -#include "platform/ptr.h" namespace location { namespace nearby { namespace connections { -template -class InternalPayloadFactory { - public: - // Creates an InternalPayload representing an outgoing Payload. - // - // The returned Ptr will take ownership of the passed-in - // 'payload'. - Ptr createOutgoing(ConstPtr payload); +// Creates an InternalPayload representing an outgoing Payload. +std::unique_ptr CreateOutgoingInternalPayload(Payload payload); - // Creates an InternalPayload representing an incoming Payload from a remote - // endpoint. - Ptr createIncoming( - const PayloadTransferFrame& payload_transfer_frame); -}; +// Creates an InternalPayload representing an incoming Payload from a remote +// endpoint. +std::unique_ptr CreateIncomingInternalPayload( + const PayloadTransferFrame& frame); } // namespace connections } // namespace nearby } // namespace location -#include "core/internal/internal_payload_factory.cc" - #endif // CORE_INTERNAL_INTERNAL_PAYLOAD_FACTORY_H_ diff --git a/cpp/core_v2/internal/internal_payload_factory_test.cc b/cpp/core/internal/internal_payload_factory_test.cc similarity index 96% rename from cpp/core_v2/internal/internal_payload_factory_test.cc rename to cpp/core/internal/internal_payload_factory_test.cc index b6d34037..24fc2f9c 100644 --- a/cpp/core_v2/internal/internal_payload_factory_test.cc +++ b/cpp/core/internal/internal_payload_factory_test.cc @@ -1,9 +1,9 @@ -#include "core_v2/internal/internal_payload_factory.h" +#include "core/internal/internal_payload_factory.h" -#include "core_v2/internal/offline_frames.h" +#include "core/internal/offline_frames.h" #include "proto/connections/offline_wire_formats.pb.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/public/pipe.h" +#include "platform/base/byte_array.h" +#include "platform/public/pipe.h" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/cpp/core/internal/loop_runner.cc b/cpp/core/internal/loop_runner.cc deleted file mode 100644 index 39414857..00000000 --- a/cpp/core/internal/loop_runner.cc +++ /dev/null @@ -1,54 +0,0 @@ -#include "core/internal/loop_runner.h" - -#include "platform/exception.h" - -namespace location { -namespace nearby { -namespace connections { - -LoopRunner::LoopRunner(const std::string& name) : name_(name) {} - -bool LoopRunner::loop(Ptr > callable) { - ScopedPtr > > scoped_callable(callable); - - onEnterLoop(); - while (true) { - onEnterIteration(); - ExceptionOr should_continue = scoped_callable->call(); - if (!should_continue.ok()) { - onExceptionExitLoop(should_continue.exception()); - break; - } - - onExitIteration(); - if (!should_continue.result()) { - onExitLoop(); - return true; - } - } - return false; -} - -void LoopRunner::onEnterLoop() { - // TODO(tracyzhou): Add logging. -} - -void LoopRunner::onEnterIteration() { - // TODO(tracyzhou): Add logging. -} - -void LoopRunner::onExitIteration() { - // TODO(tracyzhou): Add logging. -} - -void LoopRunner::onExitLoop() { - // TODO(tracyzhou): Add logging. -} - -void LoopRunner::onExceptionExitLoop(Exception::Value exception) { - // TODO(tracyzhou): Add logging. -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core/internal/loop_runner.h b/cpp/core/internal/loop_runner.h deleted file mode 100644 index af18a5c9..00000000 --- a/cpp/core/internal/loop_runner.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef CORE_INTERNAL_LOOP_RUNNER_H_ -#define CORE_INTERNAL_LOOP_RUNNER_H_ - -#include "platform/callable.h" -#include "platform/exception.h" -#include "platform/port/string.h" -#include "platform/ptr.h" - -namespace location { -namespace nearby { -namespace connections { - -// Construct to run a loop repeatedly. This class is useful to increase -// testability for multi-threaded code that runs loops; it shouldn't be used for -// general purpose loops unless tests require fine-grained control over the -// looping procedure. -class LoopRunner { - public: - explicit LoopRunner(const std::string& name); - - // Runs the provided callable repeatedly until it returns false. - // - // @return true if the loop completed successfully, false if an exception was - // encountered. - bool loop(Ptr > callable); - - protected: - void onEnterLoop(); - void onEnterIteration(); - void onExitIteration(); - void onExitLoop(); - void onExceptionExitLoop(Exception::Value exception); - - private: - const std::string name_; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_INTERNAL_LOOP_RUNNER_H_ diff --git a/cpp/core/internal/medium_manager.cc b/cpp/core/internal/medium_manager.cc deleted file mode 100644 index 4035bd20..00000000 --- a/cpp/core/internal/medium_manager.cc +++ /dev/null @@ -1,488 +0,0 @@ -#include "core/internal/medium_manager.h" - -#include "platform/synchronized.h" - -namespace location { -namespace nearby { -namespace connections { - -template -MediumManager::MediumManager() - : mediums_(new Mediums()), - bluetooth_classic_lock_(Platform::createLock()), - ble_lock_(Platform::createLock()), - wifi_lan_lock_(Platform::createLock()) {} - -template -MediumManager::~MediumManager() { - // TODO(reznor): log.atDebug().log("Initiating shutdown of MediumManager."); - Synchronized s1(bluetooth_classic_lock_.get()); - Synchronized s2(ble_lock_.get()); - Synchronized s3(wifi_lan_lock_.get()); - - mediums_.destroy(); - // TODO(reznor): log.atDebug().log("MediumManager has shut down."); -} - -// ~~~~~~~~~~~~~~~~~~~~~~~~ BLUETOOTH ~~~~~~~~~~~~~~~~~~~~~~~~ - -template -bool MediumManager::isBluetoothAvailable() { - Synchronized s(bluetooth_classic_lock_.get()); - - return mediums_->bluetoothClassic()->isAvailable(); -} - -template -bool MediumManager::turnOnBluetoothDiscoverability( - const string& device_name) { - Synchronized s(bluetooth_classic_lock_.get()); - - return mediums_->bluetoothRadio()->enable() && - mediums_->bluetoothClassic()->turnOnDiscoverability(device_name); -} - -template -void MediumManager::turnOffBluetoothDiscoverability() { - Synchronized s(bluetooth_classic_lock_.get()); - - mediums_->bluetoothClassic()->turnOffDiscoverability(); -} - -template -class DiscoveredDeviceCallback - : public BluetoothClassic::DiscoveredDeviceCallback { - public: - typedef typename MediumManager::FoundBluetoothDeviceProcessor - FoundBluetoothDeviceProcessor; - - explicit DiscoveredDeviceCallback( - Ptr found_bluetooth_device_processor) - : found_bluetooth_device_processor_(found_bluetooth_device_processor) {} - - void onDeviceDiscovered(Ptr device) override { - found_bluetooth_device_processor_->onFoundBluetoothDevice(device); - } - - void onDeviceNameChanged(Ptr device) override { - found_bluetooth_device_processor_->onFoundBluetoothDevice(device); - } - - void onDeviceLost(Ptr device) override { - found_bluetooth_device_processor_->onLostBluetoothDevice(device); - } - - private: - ScopedPtr > - found_bluetooth_device_processor_; -}; - -template -bool MediumManager::startScanningForBluetoothDevices( - Ptr found_bluetooth_device_processor) { - Synchronized s(bluetooth_classic_lock_.get()); - - return mediums_->bluetoothRadio()->enable() && - mediums_->bluetoothClassic()->startDiscovery( - MakePtr(new DiscoveredDeviceCallback( - found_bluetooth_device_processor))); -} - -template -void MediumManager::stopScanningForBluetoothDevices() { - Synchronized s(bluetooth_classic_lock_.get()); - - mediums_->bluetoothClassic()->stopDiscovery(); -} - -template -bool MediumManager::isListeningForIncomingBluetoothConnections( - const string& service_name) { - Synchronized s(bluetooth_classic_lock_.get()); - - return mediums_->bluetoothClassic()->isAcceptingConnections(service_name); -} - -template -class BluetoothAcceptedConnectionCallback - : public BluetoothClassic::AcceptedConnectionCallback { - public: - typedef typename MediumManager::IncomingBluetoothConnectionProcessor - IncomingBluetoothConnectionProcessor; - - explicit BluetoothAcceptedConnectionCallback( - Ptr - incoming_bluetooth_connection_processor) - : incoming_bluetooth_connection_processor_( - incoming_bluetooth_connection_processor) {} - - void onConnectionAccepted(Ptr socket) override { - incoming_bluetooth_connection_processor_->onIncomingBluetoothConnection( - socket); - } - - private: - ScopedPtr > - incoming_bluetooth_connection_processor_; -}; - -template -bool MediumManager::startListeningForIncomingBluetoothConnections( - const string& service_name, Ptr - incoming_bluetooth_connection_processor) { - Synchronized s(bluetooth_classic_lock_.get()); - - return mediums_->bluetoothRadio()->enable() && - mediums_->bluetoothClassic()->startAcceptingConnections( - service_name, - MakePtr(new BluetoothAcceptedConnectionCallback( - incoming_bluetooth_connection_processor))); -} - -template -void MediumManager::stopListeningForIncomingBluetoothConnections( - const string& service_name) { - Synchronized s(bluetooth_classic_lock_.get()); - - mediums_->bluetoothClassic()->stopAcceptingConnections(service_name); -} - -template -Ptr MediumManager::connectToBluetoothDevice( - Ptr bluetooth_device, const string& service_name) { - Synchronized s(bluetooth_classic_lock_.get()); - - if (!mediums_->bluetoothRadio()->enable()) { - return Ptr(); - } - - return mediums_->bluetoothClassic()->connect(bluetooth_device, service_name); -} - -// ~~~~~~~~~~~~~~~~~~~~~~~~ BLE ~~~~~~~~~~~~~~~~~~~~~~~~ -template -bool MediumManager::isBleAvailable() { - Synchronized s(ble_lock_.get()); - -#if BLE_V2_IMPLEMENTED - return mediums_->bleV2()->isAvailable(); -#else - return mediums_->ble()->isAvailable(); -#endif -} - -// TODO(ahlee): Add nearbyNotificationsBeaconData for phase 2 of implementation. -// TODO(ahlee): Add fast_advertisement_service_uuid and power_level to -// AdvertisingOptions and pass it through. -template -bool MediumManager::startBleAdvertising( - const string& service_id, ConstPtr advertisement_data) { - Synchronized s(ble_lock_.get()); - - return mediums_->bluetoothRadio()->enable() && -#if BLE_V2_IMPLEMENTED - mediums_->bleV2()->startAdvertising( - service_id, advertisement_data, BLEMediumV2::PowerMode::HIGH, - /* fast_advertisement_service_uuid= */ ""); -#else - mediums_->ble()->startAdvertising(service_id, advertisement_data); -#endif -} - -template -void MediumManager::stopBleAdvertising(const string& service_id) { - Synchronized s(ble_lock_.get()); - -#if BLE_V2_IMPLEMENTED - mediums_->bleV2()->stopAdvertising(); -#else - mediums_->ble()->stopAdvertising(); -#endif -} - -#if BLE_V2_IMPLEMENTED -template -class BLEAcceptedConnectionCallback - : public mediums::BLEV2::AcceptedConnectionCallback { - public: - BLEAcceptedConnectionCallback() {} -}; -#else -template -class BLEAcceptedConnectionCallback - : public BLE::AcceptedConnectionCallback { - public: - typedef typename MediumManager::IncomingBleConnectionProcessor - IncomingBleConnectionProcessor; - - explicit BLEAcceptedConnectionCallback( - Ptr incoming_ble_connection_processor) - : incoming_ble_connection_processor_(incoming_ble_connection_processor) {} - - void onConnectionAccepted(Ptr socket, - const string& service_id) override { - incoming_ble_connection_processor_->onIncomingBleConnection(socket, - service_id); - } - - private: - ScopedPtr > - incoming_ble_connection_processor_; -}; -#endif - -template -bool MediumManager::isListeningForIncomingBleConnections( - const string& service_id) { - Synchronized s(ble_lock_.get()); - -#if BLE_V2_IMPLEMENTED - return mediums_->bleV2()->isAcceptingConnections(); -#else - return mediums_->ble()->isAcceptingConnections(); -#endif -} - -template -bool MediumManager::startListeningForIncomingBleConnections( - const string& service_id, - Ptr incoming_ble_connection_processor) { - Synchronized s(ble_lock_.get()); - - return mediums_->bluetoothRadio()->enable() && -#if BLE_V2_IMPLEMENTED - mediums_->bleV2()->startAcceptingConnections( - service_id, - MakePtr(new BLEAcceptedConnectionCallback())); -#else - mediums_->ble()->startAcceptingConnections( - service_id, MakePtr(new BLEAcceptedConnectionCallback( - incoming_ble_connection_processor))); -#endif -} - -template -void MediumManager::stopListeningForIncomingBleConnections( - const string& service_id) { - Synchronized s(ble_lock_.get()); - -#if BLE_V2_IMPLEMENTED - mediums_->bleV2()->stopAcceptingConnections(); -#else - mediums_->ble()->stopAcceptingConnections(); -#endif -} - -template -class DiscoveredPeripheralCallback : public DISCOVERED_PERIPHERAL_CALLBACK { - public: - typedef typename MediumManager::FoundBlePeripheralProcessor - FoundBlePeripheralProcessor; - - explicit DiscoveredPeripheralCallback( - Ptr found_ble_peripheral_processor) - : found_ble_peripheral_processor_(found_ble_peripheral_processor) {} - - void onPeripheralDiscovered(Ptr ble_peripheral, - const string& service_id, -#if BLE_V2_IMPLEMENTED - ConstPtr advertisement_data, - // TODO(ahlee): Add is_fast_advertisement to - // FoundBlePeripheralProcessor. - bool is_fast_advertisement) override { -#else - ConstPtr advertisement_data) { -#endif - found_ble_peripheral_processor_->onFoundBlePeripheral( - ble_peripheral, service_id, advertisement_data); - } - - void onPeripheralLost(Ptr ble_peripheral, - const string& service_id) override { - found_ble_peripheral_processor_->onLostBlePeripheral(ble_peripheral, - service_id); - } - - private: - ScopedPtr > found_ble_peripheral_processor_; -}; - -// TODO(ahlee): Add fast_advertisement_service_uuid and power_level to -// DiscoveryOptions and pass it through. -template -bool MediumManager::startBleScanning( - const string& service_id, - Ptr found_ble_peripheral_processor) { - Synchronized s(ble_lock_.get()); - - return mediums_->bluetoothRadio()->enable() && -#if BLE_V2_IMPLEMENTED - mediums_->bleV2()->startScanning( - service_id, - MakePtr(new DiscoveredPeripheralCallback( - found_ble_peripheral_processor)), - BLEMediumV2::PowerMode::HIGH, - /* fast_advertisement_service_uuid= */ ""); -#else - mediums_->ble()->startScanning( - service_id, MakePtr(new DiscoveredPeripheralCallback( - found_ble_peripheral_processor))); -#endif -} - -template -void MediumManager::stopBleScanning(const string& service_id) { - Synchronized s(ble_lock_.get()); - -#if BLE_V2_IMPLEMENTED - mediums_->bleV2()->stopScanning(); -#else - mediums_->ble()->stopScanning(); -#endif -} - -template -Ptr MediumManager::connectToBlePeripheral( - Ptr ble_peripheral, const string& service_id) { - Synchronized s(ble_lock_.get()); - - if (!mediums_->bluetoothRadio()->enable()) { - return Ptr(); - } - -#if BLE_V2_IMPLEMENTED - // TODO(ahlee): Replace when connecting logic is implemented. - return Ptr(); -#else - return mediums_->ble()->connect(ble_peripheral, service_id); -#endif -} - -// ~~~~~~~~~~~~~~~~~~~~~~~~ WIFILAN ~~~~~~~~~~~~~~~~~~~~~~~~ -template -bool MediumManager::IsWifiLanAvailable() { - Synchronized s(wifi_lan_lock_.get()); - - return mediums_->wifi_lan()->IsAvailable(); -} - -template -bool MediumManager::StartWifiLanAdvertising( - absl::string_view service_id, absl::string_view service_info_name) { - Synchronized s(wifi_lan_lock_.get()); - - return mediums_->wifi_lan()->StartAdvertising(service_id, service_info_name); -} - -template -void MediumManager::StopWifiLanAdvertising( - absl::string_view service_id) { - Synchronized s(wifi_lan_lock_.get()); - - mediums_->wifi_lan()->StopAdvertising(service_id); -} - -template -class DiscoveredServiceCallback : public mediums::DiscoveredServiceCallback { - public: - typedef typename MediumManager::FoundWifiLanServiceProcessor - FoundWifiLanServiceProcessor; - - explicit DiscoveredServiceCallback( - Ptr found_wifi_lan_service_processor) - : found_wifi_lan_service_processor_(found_wifi_lan_service_processor) {} - - void OnServiceDiscovered(Ptr wifi_lan_service) override { - found_wifi_lan_service_processor_->OnFoundWifiLanService(wifi_lan_service); - } - - void OnServiceLost(Ptr wifi_lan_service) override { - found_wifi_lan_service_processor_->OnLostWifiLanService(wifi_lan_service); - } - - private: - ScopedPtr > - found_wifi_lan_service_processor_; -}; - -template -bool MediumManager::StartWifiLanDiscovery( - absl::string_view service_id, - Ptr found_wifi_lan_service_processor) { - Synchronized s(wifi_lan_lock_.get()); - - return mediums_->wifi_lan()->StartDiscovery( - service_id, MakePtr(new DiscoveredServiceCallback( - found_wifi_lan_service_processor))); -} - -template -void MediumManager::StopWifiLanDiscovery( - absl::string_view service_id) { - Synchronized s(wifi_lan_lock_.get()); - - mediums_->wifi_lan()->StopDiscovery(service_id); -} - -template -class WifiLanAcceptedConnectionCallback - : public mediums::WifiLan::AcceptedConnectionCallback { - public: - typedef typename MediumManager::IncomingWifiLanConnectionProcessor - IncomingWifiLanConnectionProcessor; - - explicit WifiLanAcceptedConnectionCallback( - Ptr - incoming_wifi_lan_connection_processor) - : incoming_wifi_lan_connection_processor_( - incoming_wifi_lan_connection_processor) {} - - void OnConnectionAccepted(Ptr socket, - absl::string_view service_id) override { - incoming_wifi_lan_connection_processor_->OnIncomingWifiLanConnection( - socket); - } - - private: - ScopedPtr > - incoming_wifi_lan_connection_processor_; -}; - -template -bool MediumManager::IsListeningForIncomingWifiLanConnections( - absl::string_view service_id) { - Synchronized s(wifi_lan_lock_.get()); - - return mediums_->wifi_lan()->IsAcceptingConnections(service_id); -} - -template -bool MediumManager::StartListeningForIncomingWifiLanConnections( - absl::string_view service_id, Ptr - incoming_wifi_lan_connection_processor) { - Synchronized s(wifi_lan_lock_.get()); - - return mediums_->wifi_lan()->StartAcceptingConnections( - service_id, MakePtr(new WifiLanAcceptedConnectionCallback( - incoming_wifi_lan_connection_processor))); -} - -template -void MediumManager::StopListeningForIncomingWifiLanConnections( - absl::string_view service_id) { - Synchronized s(wifi_lan_lock_.get()); - - mediums_->wifi_lan()->StopAcceptingConnections(service_id); -} - -template -Ptr MediumManager::ConnectToWifiLanService( - Ptr wifi_lan_service, absl::string_view service_id) { - Synchronized s(wifi_lan_lock_.get()); - - return mediums_->wifi_lan()->Connect(wifi_lan_service, service_id); -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core/internal/medium_manager.h b/cpp/core/internal/medium_manager.h deleted file mode 100644 index b102865a..00000000 --- a/cpp/core/internal/medium_manager.h +++ /dev/null @@ -1,180 +0,0 @@ -#ifndef CORE_INTERNAL_MEDIUM_MANAGER_H_ -#define CORE_INTERNAL_MEDIUM_MANAGER_H_ - -#include "core/internal/ble_compat.h" -#include "core/internal/mediums/mediums.h" -#include "platform/api/bluetooth_classic.h" -#include "platform/api/lock.h" -#include "platform/port/string.h" -#include "platform/ptr.h" - -namespace location { -namespace nearby { -namespace connections { - -/** - * Manages everything related to the mediums used by Nearby Connections, acting - * as a simplifying layer around the different APIs used for said management. - * - *

An overview of thread safety: - * - *

    - *
  • Methods are synchronized at a per-medium level. For example, all - * Bluetooth Classic calls are synchronized under the same - * 'bluetooth_classic_lock_'. This ensures work on a particular medium is - * well-ordered without blocking other mediums from running. Nearby - * Mediums as a whole is already threadsafe, which is why we don't need to - * synchronize at a per-radio level. - *
  • All calls are guarded by the flag 'mediums_are_available_', which - * defaults to true and is set to false in shutdown(). This flag ensures - * that no further work is done after shutdown() has been called. - * Note: shutdown() is the one and only time we grab every - * medium-specific lock, to ensure everything stops at once. - *
- * - *

Note: For methods that start an action (eg. startAdvertising()), the radio - * is first enabled. This is a prerequisite before doing any work on a medium; - * they will otherwise fail if the radio is off. Calls that stop an action (eg. - * stopAdvertising()) do not attempt to enable the radio because, if the radio - * was off, there is no work for them to stop. - */ -template -class MediumManager { - public: - MediumManager(); - ~MediumManager(); - - // ~~~~~~~~~~~~~~~~~~~~~~~~ BLUETOOTH ~~~~~~~~~~~~~~~~~~~~~~~~ - bool isBluetoothAvailable(); - - bool turnOnBluetoothDiscoverability(const string& device_name); - void turnOffBluetoothDiscoverability(); - - class FoundBluetoothDeviceProcessor { - public: - virtual ~FoundBluetoothDeviceProcessor() {} - - virtual void onFoundBluetoothDevice( - Ptr bluetooth_device) = 0; - virtual void onLostBluetoothDevice( - Ptr bluetooth_device) = 0; - }; - - bool startScanningForBluetoothDevices( - Ptr found_bluetooth_device_processor); - void stopScanningForBluetoothDevices(); - - class IncomingBluetoothConnectionProcessor { - public: - virtual ~IncomingBluetoothConnectionProcessor() {} - - virtual void onIncomingBluetoothConnection( - Ptr bluetooth_socket) = 0; - }; - - bool isListeningForIncomingBluetoothConnections(const string& service_name); - bool startListeningForIncomingBluetoothConnections( - const string& service_name, Ptr - incoming_bluetooth_connection_processor); - void stopListeningForIncomingBluetoothConnections(const string& service_name); - - Ptr connectToBluetoothDevice( - Ptr bluetooth_device, const string& service_name); - - // ~~~~~~~~~~~~~~~~~~~~~~~~ BLE ~~~~~~~~~~~~~~~~~~~~~~~~ - - bool isBleAvailable(); - - bool startBleAdvertising(const string& service_id, - ConstPtr advertisement_data); - void stopBleAdvertising(const string& service_id); - - class IncomingBleConnectionProcessor { - public: - virtual ~IncomingBleConnectionProcessor() {} - - virtual void onIncomingBleConnection(Ptr ble_socket, - const string& service_id) = 0; - }; - - bool isListeningForIncomingBleConnections(const string& service_id); - bool startListeningForIncomingBleConnections( - const string& service_id, - Ptr incoming_ble_connection_processor); - void stopListeningForIncomingBleConnections(const string& service_id); - - class FoundBlePeripheralProcessor { - public: - virtual ~FoundBlePeripheralProcessor() {} - - virtual void onFoundBlePeripheral( - Ptr ble_peripheral, const string& service_id, - ConstPtr advertisement_data) = 0; - virtual void onLostBlePeripheral(Ptr ble_peripheral, - const string& service_id) = 0; - }; - - bool startBleScanning( - const string& service_id, - Ptr found_ble_peripheral_processor); - void stopBleScanning(const string& service_id); - - Ptr connectToBlePeripheral(Ptr ble_peripheral, - const string& service_id); - - // ~~~~~~~~~~~~~~~~~~~~~~~~ WIFI-LAN ~~~~~~~~~~~~~~~~~~~~~~~~ - - bool IsWifiLanAvailable(); - - bool StartWifiLanAdvertising(absl::string_view service_id, - absl::string_view wifi_lan_service_info_name); - void StopWifiLanAdvertising(absl::string_view service_id); - - class FoundWifiLanServiceProcessor { - public: - virtual ~FoundWifiLanServiceProcessor() {} - - virtual void OnFoundWifiLanService( - Ptr wifi_lan_service) = 0; - virtual void OnLostWifiLanService(Ptr wifi_lan_service) = 0; - }; - - bool StartWifiLanDiscovery( - absl::string_view service_id, - Ptr found_wifi_lan_service_processor); - void StopWifiLanDiscovery(absl::string_view service_id); - - class IncomingWifiLanConnectionProcessor { - public: - virtual ~IncomingWifiLanConnectionProcessor() {} - - virtual void OnIncomingWifiLanConnection( - Ptr wifi_lan_socket) = 0; - }; - - bool IsListeningForIncomingWifiLanConnections(absl::string_view service_id); - bool StartListeningForIncomingWifiLanConnections( - absl::string_view service_id, Ptr - incoming_wifi_lan_connection_processor); - void StopListeningForIncomingWifiLanConnections(absl::string_view service_id); - - Ptr ConnectToWifiLanService( - Ptr wifi_lan_service, absl::string_view service_id); - - private: - // The destructor for this needs to be manually invoked after the locks below - // are acquired, so it cannot be a ScopedPtr. - Ptr > mediums_; - - ScopedPtr > bluetooth_classic_lock_; - ScopedPtr > ble_lock_; - ScopedPtr > wifi_lan_lock_; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#include "core/internal/medium_manager.cc" - -#endif // CORE_INTERNAL_MEDIUM_MANAGER_H_ diff --git a/cpp/core/internal/mediums/BUILD b/cpp/core/internal/mediums/BUILD index a8dff808..a1b900d1 100644 --- a/cpp/core/internal/mediums/BUILD +++ b/cpp/core/internal/mediums/BUILD @@ -1,134 +1,93 @@ -cc_library( - name = "utils", - srcs = [ - "utils.cc", - ], - hdrs = [ - "utils.h", - ], - visibility = [ - "//core/internal/mediums/webrtc:__pkg__", - ], - deps = [ - "//platform:types", - "//platform:utils", - "//platform/api", - "//platform/port:string", - "//absl/strings", - ], -) - cc_library( name = "mediums", srcs = [ - "ble_advertisement.cc", - "ble_advertisement_header.cc", - "ble_packet.cc", - "ble_peripheral.cc", + "ble.cc", + "bloom_filter.cc", + "bluetooth_classic.cc", + "bluetooth_radio.cc", + "mediums.cc", + "uuid.cc", + "webrtc.cc", + "wifi_lan.cc", ], hdrs = [ - "advertisement_read_result.cc", - "advertisement_read_result.h", - "ble.cc", "ble.h", - "ble_advertisement.h", - "ble_advertisement_header.h", - "ble_packet.h", - "ble_peripheral.h", - "ble_v2.cc", - "ble_v2.h", - "bloom_filter.cc", "bloom_filter.h", - "bluetooth_classic.cc", "bluetooth_classic.h", - "bluetooth_radio.cc", "bluetooth_radio.h", - "discovered_peripheral_callback.h", - "discovered_peripheral_tracker.cc", - "discovered_peripheral_tracker.h", - "lost_entity_tracker.cc", "lost_entity_tracker.h", - "mediums.cc", "mediums.h", - "uuid.cc", "uuid.h", - "wifi_lan.cc", + "webrtc.h", "wifi_lan.h", ], - visibility = ["//core/internal:__pkg__"], + visibility = [ + "//core/internal:__subpackages__", + ], deps = [ ":utils", - "//platform:logging", - "//platform:types", - "//platform:utils", - "//platform/api", - "//platform/port:string", + "//core:core_types", + "//core/internal/mediums/ble_v2", + "//core/internal/mediums/webrtc", + "//proto/connections:offline_wire_formats_portable_proto", + "//platform/base", + "//platform/public:comm", + "//platform/public:logging", + "//platform/public:types", + "//location/nearby/mediums/proto:web_rtc_signaling_frames_cc_proto", + "//absl/container:flat_hash_map", + "//absl/container:flat_hash_set", "//absl/numeric:int128", "//absl/strings", + "//absl/time", "//smhasher:libmurmur3", + "//webrtc/api:libjingle_peerconnection_api", + "//webrtc/api:scoped_refptr", + ], +) + +cc_library( + name = "utils", + srcs = ["utils.cc"], + hdrs = ["utils.h"], + visibility = [ + "//core/internal:__pkg__", + "//core/internal/mediums:__pkg__", + "//core/internal/mediums/ble_v2:__pkg__", + "//core/internal/mediums/webrtc:__pkg__", + ], + deps = [ + "//proto/connections:offline_wire_formats_portable_proto", + "//platform/base", + "//platform/public:types", ], ) cc_test( - name = "advertisement_read_result_test", - srcs = ["advertisement_read_result_test.cc"], + name = "core_internal_mediums_test", + size = "small", + srcs = [ + "ble_test.cc", + "bloom_filter_test.cc", + "bluetooth_classic_test.cc", + "bluetooth_radio_test.cc", + "lost_entity_tracker_test.cc", + "uuid_test.cc", + "webrtc_test.cc", + "wifi_lan_test.cc", + ], + shard_count = 16, deps = [ ":mediums", - "//platform/api", - "//platform/impl/g3", + "//core/internal/mediums/webrtc", + "//platform/base", + "//platform/base:test_util", + "//platform/impl/g3", # build_cleaner: keep + "//platform/public:comm", + "//platform/public:logging", + "//platform/public:types", "//testing/base/public:gunit_main", + "//absl/strings", "//absl/time", ], ) - -cc_test( - name = "ble_advertisement_header_test", - srcs = ["ble_advertisement_header_test.cc"], - deps = [ - ":mediums", - "//platform:utils", - "//platform/impl/g3", - "//testing/base/public:gunit_main", - ], -) - -cc_test( - name = "ble_advertisement_test", - srcs = ["ble_advertisement_test.cc"], - deps = [ - ":mediums", - "//platform/impl/g3", - "//testing/base/public:gunit_main", - ], -) - -cc_test( - name = "ble_packet_test", - srcs = ["ble_packet_test.cc"], - deps = [ - ":mediums", - "//platform/impl/g3", - "//testing/base/public:gunit_main", - ], -) - -cc_test( - name = "bloom_filter_test", - srcs = ["bloom_filter_test.cc"], - deps = [ - ":mediums", - "//platform/impl/g3", - "//testing/base/public:gunit_main", - ], -) - -cc_test( - name = "lost_entity_tracker_test", - srcs = ["lost_entity_tracker_test.cc"], - deps = [ - ":mediums", - "//platform/api", - "//platform/impl/g3", - "//testing/base/public:gunit_main", - ], -) diff --git a/cpp/core/internal/mediums/advertisement_read_result.cc b/cpp/core/internal/mediums/advertisement_read_result.cc deleted file mode 100644 index 12cf2e1d..00000000 --- a/cpp/core/internal/mediums/advertisement_read_result.cc +++ /dev/null @@ -1,186 +0,0 @@ -#include "core/internal/mediums/advertisement_read_result.h" - -#include - -#include "platform/synchronized.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -namespace { - -template -void eraseOwnedPtrFromMap(std::map >& m, const K& k) { - typename std::map >::iterator it = m.find(k); - if (it != m.end()) { - it->second.destroy(); - m.erase(it); - } -} - -} // namespace - -// How much to multiply the backoff duration by with every failure to read -// from the advertisement GATT server. This should never be below 1! -template -const float AdvertisementReadResult::kAdvertisementBackoffMultiplier = - 2.0; - -// The initial backoff duration when we fail to read from an advertisement -// GATT server. -template -const std::int64_t - AdvertisementReadResult::kAdvertisementBaseBackoffDurationMillis = - 1 * 1000; // 1 second - -// The maximum backoff duration allowed between advertisement GATT server -// reads. -template -const std::int64_t - AdvertisementReadResult::kAdvertisementMaxBackoffDurationMillis = - 5 * 60 * 1000; // 5 minutes - -template -AdvertisementReadResult::AdvertisementReadResult() - : lock_(Platform::createLock()), - system_clock_(Platform::createSystemClock()), - advertisements_(), - backoff_duration_millis_(kAdvertisementBaseBackoffDurationMillis), - // We need a long enough duration such that we always trigger a read - // retry AND we always connect to it without delay. The former case - // helps us initialize an AdvertisementReadResult so that we - // unconditionally try reading on the first sighting. And the latter - // case helps us connect immediately when we initialize a dummy read - // result for fast advertisements (which don't use the GATT server). - last_read_timestamp_millis_(system_clock_->elapsedRealtime() - - kAdvertisementMaxBackoffDurationMillis), - result_(Result::Value::UNKNOWN) {} - -template -AdvertisementReadResult::~AdvertisementReadResult() { - Synchronized s(lock_.get()); - - for (AdvertisementMap::iterator it = advertisements_.begin(); - it != advertisements_.end(); ++it) { - it->second.destroy(); - } - advertisements_.clear(); -} - -// Adds a successfully read advertisement for the specified slot to this read -// result. This is fundamentally different from -// {@link #recordLastReadStatus(boolean)} because we can report a read -// failure, but still manage to read some advertisements. -// Note: advertisement should be passed in as a RefCounted Ptr. It is not the -// responsibility of AdvertisementReadResult to make it RefCounted. -template -void AdvertisementReadResult::addAdvertisement( - std::int32_t slot, /* RefCounted */ ConstPtr advertisement) { - Synchronized s(lock_.get()); - - ScopedPtr> scoped_advertisement(advertisement); - - // Blindly remove from the advertisements map to make sure any existing - // key-value pair is destroyed. - eraseOwnedPtrFromMap(advertisements_, slot); - - advertisements_.insert(std::make_pair(slot, scoped_advertisement.release())); -} - -// Determines whether or not an advertisement was successfully read at the -// specified slot. -template -bool AdvertisementReadResult::hasAdvertisement(std::int32_t slot) { - Synchronized s(lock_.get()); - - return advertisements_.find(slot) != advertisements_.end(); -} - -// Retrieves all raw advertisements that were successfully read. -template -std::set> -AdvertisementReadResult::getAdvertisements() { - Synchronized s(lock_.get()); - - std::set> all_advertisements; - for (AdvertisementMap::iterator it = advertisements_.begin(); - it != advertisements_.end(); ++it) { - all_advertisements.insert(it->second); - } - - return all_advertisements; -} - -// Determines what stage we're in for retrying a read from an advertisement -// GATT server. -template -typename AdvertisementReadResult::RetryStatus::Value -AdvertisementReadResult::evaluateRetryStatus() { - Synchronized s(lock_.get()); - - // Check if we have already succeeded reading this advertisement. - if (result_ == Result::SUCCESS) { - return RetryStatus::PREVIOUSLY_SUCCEEDED; - } - - // Check if we have recently failed to read this advertisement. - if (getDurationSinceReadMillis() < backoff_duration_millis_) { - return RetryStatus::TOO_SOON; - } - - return RetryStatus::RETRY; -} - -// Records the status of the latest read, and updates the next backoff -// duration for subsequent reads. Be sure to also call -// {@link #addAdvertisement(int, byte[])} if any advertisements were read. -template -void AdvertisementReadResult::recordLastReadStatus(bool is_success) { - Synchronized s(lock_.get()); - - // Update the last read timestamp. - last_read_timestamp_millis_ = system_clock_->elapsedRealtime(); - - // Update the backoff duration. - if (is_success) { - // Reset the backoff duration now that we had a successful read. - backoff_duration_millis_ = kAdvertisementBaseBackoffDurationMillis; - } else { - // Determine whether or not we were already failing before. If we were, we - // should increase the backoff duration. - if (result_ == Result::FAILURE) { - // Use exponential backoff to determine the next backoff duration. This - // simply involves multiplying our current backoff duration by some - // multiplier. - std::int64_t next_backoff_duration = - kAdvertisementBackoffMultiplier * backoff_duration_millis_; - // Update the backoff duration, making sure not to blow past the - // ceiling. - backoff_duration_millis_ = std::min( - next_backoff_duration, kAdvertisementMaxBackoffDurationMillis); - } else { - // This is our first time failing, so we should only backoff for the - // initial duration. - backoff_duration_millis_ = kAdvertisementBaseBackoffDurationMillis; - } - } - - // Update the internal result. - result_ = is_success ? Result::SUCCESS : Result::FAILURE; -} - -// Returns how much time has passed since we last tried reading from an -// advertisement GATT server. -template -std::int64_t AdvertisementReadResult::getDurationSinceReadMillis() { - Synchronized s(lock_.get()); - - return system_clock_->elapsedRealtime() - last_read_timestamp_millis_; -} - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core/internal/mediums/advertisement_read_result.h b/cpp/core/internal/mediums/advertisement_read_result.h deleted file mode 100644 index 9fde9598..00000000 --- a/cpp/core/internal/mediums/advertisement_read_result.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef CORE_INTERNAL_MEDIUMS_ADVERTISEMENT_READ_RESULT_H_ -#define CORE_INTERNAL_MEDIUMS_ADVERTISEMENT_READ_RESULT_H_ - -#include -#include -#include - -#include "platform/api/lock.h" -#include "platform/api/system_clock.h" -#include "platform/byte_array.h" -#include "platform/ptr.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -// Representation of a GATT advertisement read result. This object helps us -// determine whether or not we need to retry GATT reads. -template -class AdvertisementReadResult { - public: - AdvertisementReadResult(); - ~AdvertisementReadResult(); - - struct RetryStatus { - enum Value { - UNKNOWN = 0, - RETRY = 1, - PREVIOUSLY_SUCCEEDED = 2, - TOO_SOON = 3, - }; - }; - - void addAdvertisement(std::int32_t slot, ConstPtr advertisement); - bool hasAdvertisement(std::int32_t slot); - std::set> getAdvertisements(); - typename RetryStatus::Value evaluateRetryStatus(); - void recordLastReadStatus(bool is_success); - std::int64_t getDurationSinceReadMillis(); - - private: - struct Result { - enum Value { UNKNOWN = 0, SUCCESS = 1, FAILURE = 2 }; - }; - - static const float kAdvertisementBackoffMultiplier; - static const std::int64_t kAdvertisementBaseBackoffDurationMillis; - static const std::int64_t kAdvertisementMaxBackoffDurationMillis; - - // ------------ GENERAL ------------ - ScopedPtr> lock_; - ScopedPtr> system_clock_; - - // ------ ADVERTISEMENTREADRESULT STATE ------ - // Maps slot numbers to the GATT advertisement found in that slot. - typedef std::map> - AdvertisementMap; - AdvertisementMap advertisements_; - - std::int64_t backoff_duration_millis_; - std::int64_t last_read_timestamp_millis_; - typename Result::Value result_; -}; - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location - -#include "core/internal/mediums/advertisement_read_result.cc" - -#endif // CORE_INTERNAL_MEDIUMS_ADVERTISEMENT_READ_RESULT_H_ diff --git a/cpp/core/internal/mediums/advertisement_read_result_test.cc b/cpp/core/internal/mediums/advertisement_read_result_test.cc deleted file mode 100644 index db251240..00000000 --- a/cpp/core/internal/mediums/advertisement_read_result_test.cc +++ /dev/null @@ -1,140 +0,0 @@ -#include "core/internal/mediums/advertisement_read_result.h" - -#include "platform/api/platform.h" -#include "gtest/gtest.h" -#include "absl/time/clock.h" -#include "absl/time/time.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -using TestPlatform = platform::ImplementationPlatform; - -constexpr char kAdvertisementBytes[] = {0x0A, 0x0B, 0x0C}; - -// Default values may be too big and impractical to wait for in the test. -// For the test platform, we redefine them to some reasonable values. -const absl::Duration kAdvertisementBaseBackoffDuration = - absl::Milliseconds(1000); // 1 second -const absl::Duration kAdvertisementMaxBackoffDuration = - absl::Milliseconds(6000); // 6 seconds - -template <> -const std::int64_t AdvertisementReadResult< - TestPlatform>::kAdvertisementMaxBackoffDurationMillis = - ToInt64Milliseconds(kAdvertisementMaxBackoffDuration); -template <> -const std::int64_t - AdvertisementReadResult< - TestPlatform>::kAdvertisementBaseBackoffDurationMillis = - ToInt64Milliseconds(kAdvertisementBaseBackoffDuration); - -TEST(AdvertisementReadResultTest, AdvertisementExists) { - AdvertisementReadResult advertisement_read_result; - advertisement_read_result.recordLastReadStatus(/* is_success= */ true); - - std::int32_t slot = 6; - advertisement_read_result.addAdvertisement( - slot, - MakeConstPtr(new ByteArray(kAdvertisementBytes, - sizeof(kAdvertisementBytes) / sizeof(char)))); - - ASSERT_TRUE(advertisement_read_result.hasAdvertisement(slot)); -} - -TEST(AdvertisementReadResultTest, AdvertisementNonExistent) { - AdvertisementReadResult advertisement_read_result; - advertisement_read_result.recordLastReadStatus(/* is_success= */ true); - - std::int32_t slot = 6; - - ASSERT_FALSE(advertisement_read_result.hasAdvertisement(slot)); -} - -TEST(AdvertisementReadResultTest, EvaluateRetryStatusInitialized) { - AdvertisementReadResult advertisement_read_result; - - ASSERT_EQ(advertisement_read_result.evaluateRetryStatus(), - AdvertisementReadResult::RetryStatus::RETRY); -} - -TEST(AdvertisementReadResultTest, EvaluateRetryStatusSuccess) { - AdvertisementReadResult advertisement_read_result; - advertisement_read_result.recordLastReadStatus(/* is_success= */ true); - - ASSERT_EQ(advertisement_read_result.evaluateRetryStatus(), - AdvertisementReadResult< - TestPlatform>::RetryStatus::PREVIOUSLY_SUCCEEDED); -} - -TEST(AdvertisementReadResultTest, EvaluateRetryStatusTooSoon) { - AdvertisementReadResult advertisement_read_result; - advertisement_read_result.recordLastReadStatus(/* is_success= */ false); - - // Sleep for some time, but not long enough to warrant a retry. - absl::SleepFor(absl::Milliseconds( - absl::ToInt64Milliseconds(kAdvertisementBaseBackoffDuration) / 2)); - - ASSERT_EQ(advertisement_read_result.evaluateRetryStatus(), - AdvertisementReadResult::RetryStatus::TOO_SOON); -} - -TEST(AdvertisementReadResultTest, EvaluateRetryStatusRetry) { - AdvertisementReadResult advertisement_read_result; - advertisement_read_result.recordLastReadStatus(/* is_success= */ false); - - // Sleep long enough to warrant a retry. - absl::SleepFor(kAdvertisementBaseBackoffDuration); - - ASSERT_EQ(advertisement_read_result.evaluateRetryStatus(), - AdvertisementReadResult::RetryStatus::RETRY); -} - -TEST(AdvertisementReadResultTest, ReportStatusExponentialBackoff) { - AdvertisementReadResult advertisement_read_result; - advertisement_read_result.recordLastReadStatus(/* is_success= */ false); - - // Record an additional failure so our backoff duration increases. - advertisement_read_result.recordLastReadStatus(/* is_success= */ false); - - // Sleep for the backoff duration. We shouldn't trigger a retry because the - // backoff should have increased from failing a second time. - absl::SleepFor(kAdvertisementBaseBackoffDuration); - - ASSERT_EQ(advertisement_read_result.evaluateRetryStatus(), - AdvertisementReadResult::RetryStatus::TOO_SOON); -} - -TEST(AdvertisementReadResultTest, ReportStatusExponentialBackoffMax) { - AdvertisementReadResult advertisement_read_result; - advertisement_read_result.recordLastReadStatus(/* is_success= */ false); - - // Record an absurd amount of failures so we hit the maximum backoff duration. - for (std::int32_t i = 0; i < 1000; i++) { - advertisement_read_result.recordLastReadStatus(/* is_success= */ false); - } - - // Sleep for the maximum backoff duration. This should be enough to warrant a - // retry. - absl::SleepFor(kAdvertisementMaxBackoffDuration); - - ASSERT_EQ(advertisement_read_result.evaluateRetryStatus(), - AdvertisementReadResult::RetryStatus::RETRY); -} - -TEST(AdvertisementReadResultTest, GetDurationSinceRead) { - AdvertisementReadResult advertisement_read_result; - advertisement_read_result.recordLastReadStatus(/* is_success= */ true); - - std::int64_t sleepTime = 420; - absl::SleepFor(absl::Milliseconds(sleepTime)); - - ASSERT_GE(advertisement_read_result.getDurationSinceReadMillis(), sleepTime); -} - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core/internal/mediums/ble.cc b/cpp/core/internal/mediums/ble.cc index ebcffbf4..5c14dd54 100644 --- a/cpp/core/internal/mediums/ble.cc +++ b/cpp/core/internal/mediums/ble.cc @@ -1,279 +1,336 @@ #include "core/internal/mediums/ble.h" -#include "platform/synchronized.h" +#include +#include +#include + +#include "core/internal/mediums/ble_v2/ble_advertisement.h" +#include "core/internal/mediums/utils.h" +#include "platform/base/prng.h" +#include "platform/public/logging.h" +#include "platform/public/mutex_lock.h" namespace location { namespace nearby { namespace connections { -template -const std::int32_t BLE::kMaxAdvertisementLength = 512; - -template -BLE::BLE(Ptr> bluetooth_radio) - : lock_(Platform::createLock()), - bluetooth_radio_(bluetooth_radio), - bluetooth_adapter_(Platform::createBluetoothAdapter()), - ble_medium_(Platform::createBLEMedium()), - scanning_info_(), - advertising_info_(), - accepting_connections_info_() {} - -template -BLE::~BLE() { - stopAdvertising(); - stopAcceptingConnections(); - stopScanning(); +ByteArray Ble::GenerateHash(const std::string& source, size_t size) { + return Utils::Sha256Hash(source, size); } -template -bool BLE::isAvailable() { - Synchronized s(lock_.get()); - - return !ble_medium_.isNull() && !bluetooth_adapter_.isNull(); +ByteArray Ble::GenerateDeviceToken() { + return Utils::Sha256Hash(std::to_string(Prng().NextUint32()), + mediums::BleAdvertisement::kDeviceTokenLength); } -// TODO(ahlee): Add fastPairData for phase 2 of C++ implementation. -template -bool BLE::startAdvertising(const string& service_id, - ConstPtr advertisement) { - Synchronized s(lock_.get()); +Ble::Ble(BluetoothRadio& radio) : radio_(radio) {} - // Avoid leaks. - ScopedPtr> scoped_advertisement(advertisement); - if (scoped_advertisement.isNull() || service_id.empty()) { - // TODO(ahlee): logger.atSevere().log("Refusing to start BLE advertising - // because a null parameter was passed in."); +bool Ble::IsAvailable() const { + MutexLock lock(&mutex_); + + return IsAvailableLocked(); +} + +bool Ble::IsAvailableLocked() const { return medium_.IsValid(); } + +bool Ble::StartAdvertising(const std::string& service_id, + const ByteArray& advertisement_bytes, + const std::string& fast_advertisement_service_uuid) { + MutexLock lock(&mutex_); + + if (advertisement_bytes.Empty()) { + NEARBY_LOGS(INFO) + << "Refusing to turn on BLE advertising. Empty advertisement data."; return false; } - if (scoped_advertisement->size() > kMaxAdvertisementLength) { - // TODO(ahlee): logger.atSevere().log("Refusing to start BLE advertising - // because the advertisement was too long. Expected at most %d bytes but - // received %d.", kMaxAdvertisementLength, advertisement->size()); + if (advertisement_bytes.size() > kMaxAdvertisementLength) { + NEARBY_LOG(INFO, + "Refusing to start BLE advertising because the advertisement " + "was too long. Expected at most %d bytes but received %d.", + kMaxAdvertisementLength, advertisement_bytes.size()); return false; } - if (isAdvertising()) { - // TODO(ahlee): logger.atSevere().log("Failed to BLE advertise because we're - // already advertising."); + if (IsAdvertisingLocked(service_id)) { + NEARBY_LOGS(INFO) + << "Failed to BLE advertise because we're already advertising."; return false; } - if (!bluetooth_radio_->isEnabled()) { - // TODO(ahlee): logger.atSevere().log("Can't start BLE advertising because - // Bluetooth isn't enabled."); + if (!radio_.IsEnabled()) { + NEARBY_LOGS(INFO) + << "Can't start BLE scanning because Bluetooth was never turned on"; return false; } - if (!isAvailable()) { - // TODO(ahlee): logger.atSevere().log("Can't start BLE advertising because - // BLE isn't enabled."); + if (!IsAvailableLocked()) { + NEARBY_LOGS(INFO) << "Can't turn on BLE advertising. BLE is not available."; return false; } - if (!ble_medium_->startAdvertising(service_id, - scoped_advertisement.release())) { - // TODO(ahlee) logger.atSevere().log("Failed to start BLE advertising"); + NEARBY_LOGS(INFO) << "Turning on BLE advertising with advertisement bytes=" + << advertisement_bytes.data() << "(" + << advertisement_bytes.size() << ")" + << ", service id=" << service_id + << ", fast advertisement service uuid=" + << fast_advertisement_service_uuid; + + // Wrap the connections advertisement to the medium advertisement. + const bool fast_advertisement = !fast_advertisement_service_uuid.empty(); + ByteArray service_id_hash{GenerateHash( + service_id, mediums::BleAdvertisement::kServiceIdHashLength)}; + ByteArray medium_advertisement_bytes{mediums::BleAdvertisement{ + mediums::BleAdvertisement::Version::kV2, + mediums::BleAdvertisement::SocketVersion::kV2, + fast_advertisement ? ByteArray{} : service_id_hash, advertisement_bytes, + GenerateDeviceToken()}}; + if (medium_advertisement_bytes.Empty()) { + NEARBY_LOGS(INFO) << "Failed to BLE advertise because we could not " + "create a medium advertisement."; return false; } - advertising_info_ = MakePtr(new AdvertisingInfo(service_id)); + if (!medium_.StartAdvertising(service_id, medium_advertisement_bytes, + fast_advertisement_service_uuid)) { + NEARBY_LOGS(INFO) + << "Failed to turn on BLE advertising with advertisement bytes=" + << advertisement_bytes.data() << "(" << advertisement_bytes.size() + << ")" + << ", fast advertisement service uuid=" + << fast_advertisement_service_uuid; + return false; + } + + advertising_info_.Add(service_id); return true; } -template -void BLE::stopAdvertising() { - Synchronized s(lock_.get()); +bool Ble::StopAdvertising(const std::string& service_id) { + MutexLock lock(&mutex_); - if (!isAdvertising()) { - // TODO(ahlee): logger.atDebug().log("Can't turn off BLE advertising because - // it never started."); - return; + if (!IsAdvertisingLocked(service_id)) { + NEARBY_LOGS(INFO) << "Can't turn off BLE advertising; it is already off"; + return false; } - ble_medium_->stopAdvertising(advertising_info_->service_id); + NEARBY_LOGS(INFO) << "Turned off BLE advertising with service id=" + << service_id; + bool ret = medium_.StopAdvertising(service_id); // Reset our bundle of advertising state to mark that we're no longer // advertising. - advertising_info_.destroy(); - - // TODO(ahlee): logger.atVerbose().log("Turned BLE advertising off"); + advertising_info_.Remove(service_id); + return ret; } -template -bool BLE::isAdvertising() { - Synchronized s(lock_.get()); +bool Ble::IsAdvertising(const std::string& service_id) { + MutexLock lock(&mutex_); - return !advertising_info_.isNull(); + return IsAdvertisingLocked(service_id); } -template -bool BLE::startScanning( - const string& service_id, - Ptr discovered_peripheral_callback) { - Synchronized s(lock_.get()); +bool Ble::IsAdvertisingLocked(const std::string& service_id) { + return advertising_info_.Existed(service_id); +} - // Avoid leaks. - ScopedPtr> - scoped_discovered_peripheral_callback(discovered_peripheral_callback); - if (scoped_discovered_peripheral_callback.isNull() || service_id.empty()) { - // TODO(ahlee): logger.atSevere().log("Refusing to start BLE scanning - // because a null parameter was passed in."); +bool Ble::StartScanning(const std::string& service_id, + const std::string& fast_advertisement_service_uuid, + DiscoveredPeripheralCallback callback) { + MutexLock lock(&mutex_); + + discovered_peripheral_callback_ = std::move(callback); + + if (service_id.empty()) { + NEARBY_LOGS(INFO) + << "Refusing to start BLE scanning with empty service id."; return false; } - if (isScanning()) { - // TODO(ahlee): logger.atSevere().log("Refusing to start BLE scanning - // because we are already scanning."); + if (IsScanningLocked(service_id)) { + NEARBY_LOGS(INFO) << "Refusing to start scan of BLE peripherals because " + "another scanning is already in-progress."; return false; } - if (!bluetooth_radio_->isEnabled()) { - // TODO(ahlee): logger.atSevere().log("Can't start BLE scanning because - // Bluetooth was never turned on"); + if (!radio_.IsEnabled()) { + NEARBY_LOGS(INFO) + << "Can't start BLE scanning because Bluetooth was never turned on"; return false; } - if (!isAvailable()) { - // TODO(ahlee): logger.atSevere().log("Can't start BLE scanning because - // BLE isn't available."); + if (!IsAvailableLocked()) { + NEARBY_LOGS(INFO) + << "Can't scan BLE peripherals because BLE isn't available."; return false; } - // Avoid leaks. - ScopedPtr> - scoped_ble_discovered_peripheral_callback( - new BLEDiscoveredPeripheralCallback( - scoped_discovered_peripheral_callback.release())); - if (!ble_medium_->startScanning( - service_id, scoped_ble_discovered_peripheral_callback.get())) { - // TODO(ahlee): logger.atSevere().log("Failed to start BLE scanning."); + if (!medium_.StartScanning( + service_id, fast_advertisement_service_uuid, + { + .peripheral_discovered_cb = + [this](BlePeripheral& peripheral, + const std::string& service_id, + const ByteArray& medium_advertisement_bytes, + bool fast_advertisement) { + // Unwrap connection BleAdvertisement from medium + // BleAdvertisement. + auto connection_advertisement_bytes = + UnwrapAdvertisementBytes(medium_advertisement_bytes); + discovered_peripheral_callback_.peripheral_discovered_cb( + peripheral, service_id, connection_advertisement_bytes, + fast_advertisement); + }, + .peripheral_lost_cb = + [this](BlePeripheral& peripheral, + const std::string& service_id) { + discovered_peripheral_callback_.peripheral_lost_cb( + peripheral, service_id); + }, + })) { + NEARBY_LOGS(INFO) << "Failed to start scan of BLE services."; return false; } - scanning_info_ = MakePtr(new ScanningInfo( - service_id, scoped_ble_discovered_peripheral_callback.release())); + NEARBY_LOGS(INFO) << "Turned on BLE scanning with service id=" << service_id; + // Mark the fact that we're currently performing a BLE discovering. + scanning_info_.Add(service_id); return true; } -template -void BLE::stopScanning() { - Synchronized s(lock_.get()); +bool Ble::StopScanning(const std::string& service_id) { + MutexLock lock(&mutex_); - if (!isScanning()) { - // TODO(ahlee): logger.atDebug().log("Can't turn off BLE scanning because we - // never started scanning."); - return; + if (!IsScanningLocked(service_id)) { + NEARBY_LOGS(INFO) << "Can't turn off BLE sacanning because we never " + "started scanning."; + return false; } - ble_medium_->stopScanning(scanning_info_->service_id); - // Reset our bundle of scanning state to mark that we're no longer scanning. - scanning_info_.destroy(); + NEARBY_LOG(INFO, "Turned off BLE scanning with service id=%s", + service_id.c_str()); + bool ret = medium_.StopScanning(service_id); + scanning_info_.Clear(); + return ret; } -template -bool BLE::isScanning() { - Synchronized s(lock_.get()); +bool Ble::IsScanning(const std::string& service_id) { + MutexLock lock(&mutex_); - return !scanning_info_.isNull(); + return IsScanningLocked(service_id); } -template -bool BLE::startAcceptingConnections( - const string& service_id, - Ptr accepted_connection_callback) { - Synchronized s(lock_.get()); +bool Ble::IsScanningLocked(const std::string& service_id) { + return scanning_info_.Existed(service_id); +} - // Avoid leaks. - ScopedPtr> - scoped_accepted_connection_callback(accepted_connection_callback); - if (scoped_accepted_connection_callback.isNull() || service_id.empty()) { - // TODO(ahlee): logger.atSevere().log("Refusing to start accepting BLE - // connections because a null parameter was passed in."); +bool Ble::StartAcceptingConnections(const std::string& service_id, + AcceptedConnectionCallback callback) { + MutexLock lock(&mutex_); + + if (service_id.empty()) { + NEARBY_LOGS(INFO) + << "Refusing to start accepting BLE connections with empty service id."; return false; } - if (isAcceptingConnections()) { - // TODO(ahlee): logger.atSevere().log("Refusing to start accepting BLE - // connections for %s because another BLE server socket is already - // in-progress.", service_id); + if (IsAcceptingConnectionsLocked(service_id)) { + NEARBY_LOGS(INFO) + << "Refusing to start accepting BLE connections for " + << service_id + << " because another BLE peripheral socket is already in-progress."; return false; } - if (!bluetooth_radio_->isEnabled()) { - // TODO(ahlee): logger.atSevere().log("Can't start accepting BLE connections - // for %s because Bluetooth isn't enabled.", serviceId); + if (!radio_.IsEnabled()) { + NEARBY_LOGS(INFO) << "Can't start accepting BLE connections for " + << service_id + << " because Bluetooth isn't enabled."; return false; } - if (!isAvailable()) { - // TODO(ahlee): logger.atSevere().log("Can't start accepting BLE connections - // for %s because BLE isn't available.", serviceId); + if (!IsAvailableLocked()) { + NEARBY_LOGS(INFO) << "Can't start accepting BLE connections for " + << service_id << " because BLE isn't available."; return false; } - // Avoid leaks. - ScopedPtr> - scoped_ble_accepted_connection_callback(new BLEAcceptedConnectionCallback( - scoped_accepted_connection_callback.release())); - if (!ble_medium_->startAcceptingConnections( - service_id, scoped_ble_accepted_connection_callback.get())) { + if (!medium_.StartAcceptingConnections(service_id, callback)) { + NEARBY_LOGS(INFO) << "Failed to accept connections callback for " + << service_id << " ."; return false; } - accepting_connections_info_ = MakePtr(new AcceptingConnectionsInfo( - service_id, scoped_ble_accepted_connection_callback.release())); + accepting_connections_info_.Add(service_id); return true; } -template -void BLE::stopAcceptingConnections() { - Synchronized s(lock_.get()); +bool Ble::StopAcceptingConnections(const std::string& service_id) { + MutexLock lock(&mutex_); - if (!isAcceptingConnections()) { - // TODO(ahlee): logger.atDebug().log("Can't stop accepting BLE connections - // because it was never started."); - return; + if (!IsAcceptingConnectionsLocked(service_id)) { + NEARBY_LOGS(INFO) + << "Can't stop accepting BLE connections because it was never started."; + return false; } - ble_medium_->stopAcceptingConnections( - accepting_connections_info_->service_id); + bool ret = medium_.StopAcceptingConnections(service_id); // Reset our bundle of accepting connections state to mark that we're no // longer accepting connections. - accepting_connections_info_.destroy(); + accepting_connections_info_.Remove(service_id); + return ret; } -template -bool BLE::isAcceptingConnections() { - Synchronized s(lock_.get()); +bool Ble::IsAcceptingConnections(const std::string& service_id) { + MutexLock lock(&mutex_); - return !accepting_connections_info_.isNull(); + return IsAcceptingConnectionsLocked(service_id); } -template -Ptr BLE::connect(Ptr ble_peripheral, - const string& service_id) { - Synchronized s(lock_.get()); +bool Ble::IsAcceptingConnectionsLocked(const std::string& service_id) { + return accepting_connections_info_.Existed(service_id); +} - if (ble_peripheral.isNull() || service_id.empty()) { - // TODO(ahlee): logger.atSevere().log("Refusing to create client BLE socket - // because at least one of blePeripheral or serviceId is null."); - return Ptr(); +BleSocket Ble::Connect(BlePeripheral& peripheral, + const std::string& service_id) { + MutexLock lock(&mutex_); + NEARBY_LOGS(INFO) << "BLE::Connect: service=" << &peripheral; + // Socket to return. To allow for NRVO to work, it has to be a single object. + BleSocket socket; + + if (service_id.empty()) { + NEARBY_LOGS(INFO) << "Refusing to create BLE socket with empty service_id."; + return socket; } - if (!bluetooth_radio_->isEnabled()) { - // TODO(ahlee): logger.atSevere().log("Can't create client BLE socket to %s - // because Bluetooth isn't enabled.", blePeripheral); - return Ptr(); + if (!radio_.IsEnabled()) { + NEARBY_LOGS(INFO) << "Can't create client BLE socket to " + << &peripheral << " because Bluetooth isn't enabled."; + return socket; } - if (!isAvailable()) { - // TODO(ahlee): logger.atSevere().log("Can't create client BLE socket to %s - // because BLE isn't available.", blePeripheral); - return Ptr(); + if (!IsAvailableLocked()) { + NEARBY_LOGS(INFO) << "Can't create client BLE socket [service_id=" + << service_id << "]; BLE isn't available."; + return socket; } - return ble_medium_->connect(ble_peripheral, service_id); + socket = medium_.Connect(peripheral, service_id); + if (!socket.IsValid()) { + NEARBY_LOGS(INFO) << "Failed to Connect via BLE [service=" << service_id + << "]"; + } + + return socket; +} + +ByteArray Ble::UnwrapAdvertisementBytes( + const ByteArray& medium_advertisement_data) { + mediums::BleAdvertisement medium_ble_advertisement{medium_advertisement_data}; + if (!medium_ble_advertisement.IsValid()) { + return ByteArray{}; + } + + return medium_ble_advertisement.GetData(); } } // namespace connections diff --git a/cpp/core/internal/mediums/ble.h b/cpp/core/internal/mediums/ble.h index e7db1336..83f7ed3f 100644 --- a/cpp/core/internal/mediums/ble.h +++ b/cpp/core/internal/mediums/ble.h @@ -2,196 +2,171 @@ #define CORE_INTERNAL_MEDIUMS_BLE_H_ #include +#include #include "core/internal/mediums/bluetooth_radio.h" -#include "platform/api/ble.h" -#include "platform/api/bluetooth_adapter.h" -#include "platform/api/lock.h" -#include "platform/byte_array.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "core/listeners.h" +#include "platform/base/byte_array.h" +#include "platform/public/ble.h" +#include "platform/public/multi_thread_executor.h" +#include "platform/public/mutex.h" +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" namespace location { namespace nearby { namespace connections { -template -class BLE { +class Ble { public: - explicit BLE(Ptr> bluetooth_radio); - ~BLE(); + using DiscoveredPeripheralCallback = BleMedium::DiscoveredPeripheralCallback; + using AcceptedConnectionCallback = BleMedium::AcceptedConnectionCallback; - bool isAvailable(); + explicit Ble(BluetoothRadio& bluetooth_radio); + ~Ble() = default; - bool startAdvertising(const string& service_id, - ConstPtr advertisement); - void stopAdvertising(); + // Returns true, if Ble communications are supported by a platform. + bool IsAvailable() const ABSL_LOCKS_EXCLUDED(mutex_); - class DiscoveredPeripheralCallback { - public: - virtual ~DiscoveredPeripheralCallback() {} + // Sets custom advertisement data, and then enables Ble advertising. + // Returns true, if data is successfully set, and false otherwise. + bool StartAdvertising(const std::string& service_id, + const ByteArray& advertisement_bytes, + const std::string& fast_advertisement_service_uuid) + ABSL_LOCKS_EXCLUDED(mutex_); - virtual void onPeripheralDiscovered(Ptr ble_peripheral, - const string& service_id, - ConstPtr advertisement) = 0; - virtual void onPeripheralLost(Ptr ble_peripheral, - const string& service_id) = 0; - }; + // Disables Ble advertising. + bool StopAdvertising(const std::string& service_id) + ABSL_LOCKS_EXCLUDED(mutex_); - bool startScanning( - const string& service_id, - Ptr discovered_peripheral_callback); - void stopScanning(); + bool IsAdvertising(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_); - class AcceptedConnectionCallback { - public: - virtual ~AcceptedConnectionCallback() {} + // Enables Ble scanning mode. Will report any discoverable peripherals in + // range through a callback. Returns true, if scanning mode was enabled, + // false otherwise. + bool StartScanning(const std::string& service_id, + const std::string& fast_advertisement_service_uuid, + DiscoveredPeripheralCallback callback) + ABSL_LOCKS_EXCLUDED(mutex_); - virtual void onConnectionAccepted(Ptr socket, - const string& service_id) = 0; - }; + // Disables Ble discovery mode. + bool StopScanning(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_); - bool startAcceptingConnections( - const string& service_id, - Ptr accepted_connection_callback); - void stopAcceptingConnections(); - bool isAcceptingConnections(); + bool IsScanning(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_); - Ptr connect(Ptr ble_peripheral, - const string& service_id); + // Starts a worker thread, creates a Ble socket, associates it with a + // service id. + bool StartAcceptingConnections(const std::string& service_id, + AcceptedConnectionCallback callback) + ABSL_LOCKS_EXCLUDED(mutex_); + + // Closes socket corresponding to a service id. + bool StopAcceptingConnections(const std::string& service_id) + ABSL_LOCKS_EXCLUDED(mutex_); + + bool IsAcceptingConnections(const std::string& service_id) + ABSL_LOCKS_EXCLUDED(mutex_); + + // Returns true if this object owns a valid platform implementation. + bool IsMediumValid() const ABSL_LOCKS_EXCLUDED(mutex_) { + MutexLock lock(&mutex_); + return medium_.IsValid(); + } + + // Returns true if this object has a valid BluetoothAdapter reference. + bool IsAdapterValid() const ABSL_LOCKS_EXCLUDED(mutex_) { + MutexLock lock(&mutex_); + return adapter_.IsValid(); + } + + // Establishes connection to Ble peripheral that was might be started on + // another peripheral with StartAcceptingConnections() using the same + // service_id. Blocks until connection is established, or server-side is + // terminated. Returns socket instance. On success, BleSocket.IsValid() return + // true. + BleSocket Connect(BlePeripheral& peripheral, const std::string& service_id) + ABSL_LOCKS_EXCLUDED(mutex_); private: - // TODO(ahlee): Rename to DiscoveredPeripheralCallbackBridge - class BLEDiscoveredPeripheralCallback - : public BLEMedium::DiscoveredPeripheralCallback { - public: - explicit BLEDiscoveredPeripheralCallback( - Ptr discovered_peripheral_callback) - : discovered_peripheral_callback_(discovered_peripheral_callback) {} - ~BLEDiscoveredPeripheralCallback() override { - // Nothing to do. + struct AdvertisingInfo { + bool Empty() const { return service_ids.empty(); } + void Clear() { service_ids.clear(); } + void Add(const std::string& service_id) { service_ids.emplace(service_id); } + void Remove(const std::string& service_id) { + service_ids.erase(service_id); + } + bool Existed(const std::string& service_id) const { + return service_ids.contains(service_id); } - void onPeripheralDiscovered(Ptr ble_peripheral, - const string& service_id, - ConstPtr advertisement) override { - discovered_peripheral_callback_->onPeripheralDiscovered( - ble_peripheral, service_id, advertisement); - } - void onPeripheralLost(Ptr ble_peripheral, - const string& service_id) override { - discovered_peripheral_callback_->onPeripheralLost(ble_peripheral, - service_id); - } - - private: - ScopedPtr> - discovered_peripheral_callback_; - }; - - // TODO(ahlee): Rename to AcceptedConnectionCallbackBridge - class BLEAcceptedConnectionCallback - : public BLEMedium::AcceptedConnectionCallback { - public: - explicit BLEAcceptedConnectionCallback( - Ptr accepted_connection_callback) - : accepted_connection_callback_(accepted_connection_callback) {} - ~BLEAcceptedConnectionCallback() override { - // Nothing to do. - } - - void onConnectionAccepted(Ptr ble_socket, - const string& service_id) override { - accepted_connection_callback_->onConnectionAccepted(ble_socket, - service_id); - } - - private: - ScopedPtr> - accepted_connection_callback_; + absl::flat_hash_set service_ids; }; struct ScanningInfo { - ScanningInfo( - const string& service_id, - Ptr ble_discovered_peripheral_callback) - : service_id(service_id), - ble_discovered_peripheral_callback( - ble_discovered_peripheral_callback) {} - ~ScanningInfo() { - // Nothing to do (the ScopedPtr members take care of themselves). + bool Empty() const { return service_ids.empty(); } + void Clear() { service_ids.clear(); } + void Add(const std::string& service_id) { service_ids.emplace(service_id); } + void Remove(const std::string& service_id) { + service_ids.erase(service_id); + } + bool Existed(const std::string& service_id) const { + return service_ids.contains(service_id); } - const string service_id; - ScopedPtr> - ble_discovered_peripheral_callback; - }; - - struct AdvertisingInfo { - explicit AdvertisingInfo(const string& service_id) - : service_id(service_id) {} - ~AdvertisingInfo() {} - - const string service_id; + absl::flat_hash_set service_ids; }; struct AcceptingConnectionsInfo { - AcceptingConnectionsInfo( - const string& service_id, - Ptr ble_accepted_connection_callback) - : service_id(service_id), - ble_accepted_connection_callback(ble_accepted_connection_callback) {} - ~AcceptingConnectionsInfo() { - // Nothing to do (the ScopedPtr members take care of themselves). + bool Empty() const { return service_ids.empty(); } + void Clear() { service_ids.clear(); } + void Add(const std::string& service_id) { service_ids.emplace(service_id); } + void Remove(const std::string& service_id) { + service_ids.erase(service_id); + } + bool Existed(const std::string& service_id) const { + return service_ids.contains(service_id); } - const string service_id; - ScopedPtr> - ble_accepted_connection_callback; + absl::flat_hash_set service_ids; }; - static const std::int32_t kMaxAdvertisementLength; + static constexpr int kMaxAdvertisementLength = 512; - bool isAdvertising(); - bool isScanning(); + static ByteArray GenerateHash(const std::string& source, size_t size); + static ByteArray GenerateDeviceToken(); - // ------------ GENERAL ------------ + // Same as IsAvailable(), but must be called with mutex_ held. + bool IsAvailableLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - ScopedPtr> lock_; + // Same as IsAdvertising(), but must be called with mutex_ held. + bool IsAdvertisingLocked(const std::string& service_id) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - // ------------ CORE BLE ------------ + // Same as IsDiscovering(), but must be called with mutex_ held. + bool IsScanningLocked(const std::string& service_id) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - Ptr> bluetooth_radio_; - ScopedPtr> bluetooth_adapter_; - // The underlying, per-platform implementation. - ScopedPtr> ble_medium_; + // Same as IsAcceptingConnections(), but must be called with mutex_ held. + bool IsAcceptingConnectionsLocked(const std::string& service_id) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - // ------------ DISCOVERY ------------ + // Extract connection advertisement from medium advertisement. + ByteArray UnwrapAdvertisementBytes( + const ByteArray& medium_advertisement_data); - // A bundle of state required to start/stop BLE scanning. When non-null, - // we are currently performing a BLE scan. - // In the Java code this maps to the bleListener and - // bleScanningMediumOperation. - Ptr scanning_info_; - - // ------------ ADVERTISING ------------ - - // A bundle of state required to start/stop BLE advertising. When non-null, - // we are currently advertising over BLE. - // In the Java code this maps to bleAdvertiser, advertiseCallback, and - // bleAdvertisingMediumOperation. - Ptr advertising_info_; - - // A bundle of state required to start/stop accepting BLE connections. When - // non-null, we are currently accepting BLE connections. - // In the Java code this maps to the bleServerSocket. - Ptr accepting_connections_info_; + mutable Mutex mutex_; + BluetoothRadio& radio_ ABSL_GUARDED_BY(mutex_); + BluetoothAdapter& adapter_ ABSL_GUARDED_BY(mutex_){ + radio_.GetBluetoothAdapter()}; + BleMedium medium_ ABSL_GUARDED_BY(mutex_){adapter_}; + AdvertisingInfo advertising_info_ ABSL_GUARDED_BY(mutex_); + ScanningInfo scanning_info_ ABSL_GUARDED_BY(mutex_); + DiscoveredPeripheralCallback discovered_peripheral_callback_; + AcceptingConnectionsInfo accepting_connections_info_ ABSL_GUARDED_BY(mutex_); }; } // namespace connections } // namespace nearby } // namespace location -#include "core/internal/mediums/ble.cc" - #endif // CORE_INTERNAL_MEDIUMS_BLE_H_ diff --git a/cpp/core/internal/mediums/ble_advertisement.cc b/cpp/core/internal/mediums/ble_advertisement.cc deleted file mode 100644 index 050c51a1..00000000 --- a/cpp/core/internal/mediums/ble_advertisement.cc +++ /dev/null @@ -1,288 +0,0 @@ -#include "core/internal/mediums/ble_advertisement.h" - -#include "platform/logging.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -const std::uint32_t BLEAdvertisement::kServiceIdHashLength = 3; - -const std::uint32_t BLEAdvertisement::kVersionLength = 1; -// Length of one int. Be sure to re-evaluate how we compute data size in this -// class if this constant ever changes! -const std::uint32_t BLEAdvertisement::kDataSizeLength = 4; -const std::uint32_t BLEAdvertisement::kMinAdvertisementLength = - kVersionLength + kServiceIdHashLength + kDataSizeLength; -// The maximum length for a GATT characteristic value is 512 bytes, so make sure -// the entire advertisement is less than that. The data can take up whatever -// space is remaining after the bytes preceding it. -const std::uint32_t BLEAdvertisement::kMaxDataSize = - 512 - kMinAdvertisementLength; -const std::uint16_t BLEAdvertisement::kVersionBitmask = 0x0E0; -const std::uint16_t BLEAdvertisement::kSocketVersionBitmask = 0x01C; - -ConstPtr BLEAdvertisement::fromBytes( - ConstPtr ble_advertisement_bytes) { - if (ble_advertisement_bytes.isNull()) { - NEARBY_LOG(INFO, - "Cannot deserialize BLEAdvertisement: null bytes passed in"); - return ConstPtr(); - } - - if (ble_advertisement_bytes->size() < kMinAdvertisementLength) { - NEARBY_LOG(INFO, - "Cannot deserialize BLEAdvertisement: expecting min %u raw " - "bytes, got %zu", - kMinAdvertisementLength, ble_advertisement_bytes->size()); - return ConstPtr(); - } - - // Now, time to read the bytes! - const char *ble_advertisement_bytes_read_ptr = - ble_advertisement_bytes->getData(); - - // 1. Version. - Version::Value version = parseVersionFromByte( - static_cast(*ble_advertisement_bytes_read_ptr)); - if (!isSupportedVersion(version)) { - NEARBY_LOG(INFO, - "Cannot deserialize BLEAdvertisement: unsupported Version %u", - version); - return ConstPtr(); - } - - // 2. Socket Version. - SocketVersion::Value socket_version = parseSocketVersionFromByte( - static_cast(*ble_advertisement_bytes_read_ptr)); - if (!isSupportedSocketVersion(socket_version)) { - NEARBY_LOG( - INFO, - "Cannot deserialize BLEAdvertisement: unsupported SocketVersion %u", - socket_version); - return ConstPtr(); - } - ble_advertisement_bytes_read_ptr += kVersionLength; - - // 3. Service ID hash. - ScopedPtr > scoped_service_id_hash(MakeConstPtr( - new ByteArray(ble_advertisement_bytes_read_ptr, kServiceIdHashLength))); - ble_advertisement_bytes_read_ptr += kServiceIdHashLength; - - // 4.1. Data size. - size_t expected_data_size = - deserializeDataSize(ble_advertisement_bytes_read_ptr); - if (expected_data_size < 0) { - NEARBY_LOG(INFO, - "Cannot deserialize BLEAdvertisement: negative data size %zu", - expected_data_size); - return ConstPtr(); - } - ble_advertisement_bytes_read_ptr += kDataSizeLength; - - // Check that the stated data size is the same as what we received. - size_t actual_data_size = computeDataSize(ble_advertisement_bytes); - if (actual_data_size < expected_data_size) { - NEARBY_LOG(INFO, - "Cannot deserialize BLEAdvertisement: expected data to be %zu " - "bytes, got %zu bytes", - expected_data_size, actual_data_size); - return ConstPtr(); - } - - // 4.2. Data. - ScopedPtr > scoped_data(MakeConstPtr( - new ByteArray(ble_advertisement_bytes_read_ptr, expected_data_size))); - ble_advertisement_bytes_read_ptr += expected_data_size; - - return MakeRefCountedConstPtr(new BLEAdvertisement( - version, socket_version, scoped_service_id_hash.release(), - scoped_data.release())); -} - -ConstPtr BLEAdvertisement::toBytes( - Version::Value version, SocketVersion::Value socket_version, - ConstPtr service_id_hash, ConstPtr data) { - // Check that the given input is valid. - if (!isSupportedVersion(version)) { - NEARBY_LOG(INFO, - "Cannot serialize BLEAdvertisement: unsupported Version %u", - version); - return ConstPtr(); - } - - if (!isSupportedSocketVersion(socket_version)) { - NEARBY_LOG( - INFO, "Cannot serialize BLEAdvertisement: unsupported SocketVersion %u", - socket_version); - return ConstPtr(); - } - - if (service_id_hash->size() != kServiceIdHashLength) { - NEARBY_LOG(INFO, - "Cannot serialize BLEAdvertisement: expected a service_id_hash " - "of %u bytes, but got %zu", - kServiceIdHashLength, service_id_hash->size()); - return ConstPtr(); - } - - if (data->size() > kMaxDataSize) { - NEARBY_LOG(INFO, - "Cannot serialize BLEAdvertisement: expected data of at most %u " - "bytes, but got %zu", - kMaxDataSize, data->size()); - return ConstPtr(); - } - - // Initialize the bytes. - size_t advertisement_length = computeAdvertisementLength(data); - Ptr advertisement_bytes{new ByteArray{advertisement_length}}; - char *advertisement_bytes_write_ptr = advertisement_bytes->getData(); - - // 1. Version. - serializeVersionByte(advertisement_bytes_write_ptr, version); - - // 2. SocketVersion. - serializeSocketVersionByte(advertisement_bytes_write_ptr, socket_version); - advertisement_bytes_write_ptr += kVersionLength; - - // 3. Service ID hash. - memcpy(advertisement_bytes_write_ptr, service_id_hash->getData(), - kServiceIdHashLength); - advertisement_bytes_write_ptr += kServiceIdHashLength; - - // 4.1. Data length. - serializeDataSize(advertisement_bytes_write_ptr, data->size()); - advertisement_bytes_write_ptr += kDataSizeLength; - - // 4.2. Data. - memcpy(advertisement_bytes_write_ptr, data->getData(), data->size()); - advertisement_bytes_write_ptr += data->size(); - - return ConstifyPtr(advertisement_bytes); -} - -bool BLEAdvertisement::isSupportedVersion(Version::Value version) { - return version >= Version::V1 && version <= Version::V2; -} - -bool BLEAdvertisement::isSupportedSocketVersion( - SocketVersion::Value socket_version) { - return socket_version >= SocketVersion::V1 && - socket_version <= SocketVersion::V2; -} - -BLEAdvertisement::Version::Value BLEAdvertisement::parseVersionFromByte( - std::uint16_t byte) { - return static_cast( - (byte & kVersionBitmask) >> 5); -} - -BLEAdvertisement::SocketVersion::Value -BLEAdvertisement::parseSocketVersionFromByte(std::uint16_t byte) { - return static_cast((byte & kSocketVersionBitmask) >> 2); -} - -size_t BLEAdvertisement::deserializeDataSize( - const char *data_size_bytes_read_ptr) { - // Allocate a chunk of memory to store our deserialized size. - char data_size_bytes[kDataSizeLength]; - - // Assign the bits of our size from the given raw bytes, keeping in mind that - // we need to convert from Big Endian to Little Endian in the process. - for (int i = 0; i < kDataSizeLength; ++i) { - data_size_bytes[i] = data_size_bytes_read_ptr[kDataSizeLength - i - 1]; - } - - // Interpret the char array as a single int. - return static_cast( - *(reinterpret_cast(&data_size_bytes))); -} - -size_t BLEAdvertisement::computeDataSize( - ConstPtr ble_advertisement_bytes) { - return ble_advertisement_bytes->size() - kMinAdvertisementLength; -} - -size_t BLEAdvertisement::computeAdvertisementLength(ConstPtr data) { - // The advertisement length is the minimum length + the length of the data. - return kMinAdvertisementLength + data->size(); -} - -void BLEAdvertisement::serializeVersionByte(char *version_byte_write_ptr, - Version::Value version) { - *version_byte_write_ptr |= - static_cast((version << 5) & kVersionBitmask); -} - -void BLEAdvertisement::serializeSocketVersionByte( - char *socket_version_byte_write_ptr, SocketVersion::Value socket_version) { - *socket_version_byte_write_ptr |= - static_cast((socket_version << 2) & kSocketVersionBitmask); -} - -void BLEAdvertisement::serializeDataSize(char *data_size_bytes_write_ptr, - size_t data_size) { - // Get a raw representation of the data size bytes in memory. - char *data_size_bytes = reinterpret_cast(&data_size); - - // Append these raw bytes to advertisement bytes, keeping in mind that we need - // to convert from Little Endian to Big Endian in the process. - for (int i = 0; i < kDataSizeLength; ++i) { - data_size_bytes_write_ptr[i] = data_size_bytes[kDataSizeLength - i - 1]; - } -} - -BLEAdvertisement::BLEAdvertisement(Version::Value version, - SocketVersion::Value socket_version, - ConstPtr service_id_hash, - ConstPtr data) - : version_(version), - socket_version_(socket_version), - service_id_hash_(service_id_hash), - data_(data) {} - -BLEAdvertisement::~BLEAdvertisement() { - // Nothing to do. -} - -BLEAdvertisement::Version::Value BLEAdvertisement::getVersion() const { - return version_; -} - -BLEAdvertisement::SocketVersion::Value BLEAdvertisement::getSocketVersion() - const { - return socket_version_; -} - -ConstPtr BLEAdvertisement::getServiceIdHash() const { - return service_id_hash_.get(); -} - -ConstPtr BLEAdvertisement::getData() const { return data_.get(); } - -bool BLEAdvertisement::operator==(const BLEAdvertisement &rhs) const { - return this->getVersion() == rhs.getVersion() && - this->getSocketVersion() == rhs.getSocketVersion() && - *(this->getServiceIdHash()) == *(rhs.getServiceIdHash()) && - *(this->getData()) == *(rhs.getData()); -} - -bool BLEAdvertisement::operator<(const BLEAdvertisement &rhs) const { - if (this->getVersion() != rhs.getVersion()) { - return this->getVersion() < rhs.getVersion(); - } - if (this->getSocketVersion() != rhs.getSocketVersion()) { - return this->getSocketVersion() < rhs.getSocketVersion(); - } - if (*(this->getServiceIdHash()) != *(rhs.getServiceIdHash())) { - return *(this->getServiceIdHash()) < *(rhs.getServiceIdHash()); - } - return *(this->getData()) < *(rhs.getData()); -} - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core/internal/mediums/ble_advertisement.h b/cpp/core/internal/mediums/ble_advertisement.h deleted file mode 100644 index 75209336..00000000 --- a/cpp/core/internal/mediums/ble_advertisement.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef CORE_INTERNAL_MEDIUMS_BLE_ADVERTISEMENT_H_ -#define CORE_INTERNAL_MEDIUMS_BLE_ADVERTISEMENT_H_ - -#include "platform/byte_array.h" -#include "platform/ptr.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -// Represents the format of the Mediums BLE Advertisement used in advertising -// and discovery. -// -// [VERSION][SOCKET_VERSION][2_RESERVED_BITS][SERVICE_ID_HASH][DATA_SIZE][DATA] -// -// See go/nearby-ble-design for more information. -class BLEAdvertisement { - public: - // Versions of the BLEAdvertisement. - struct Version { - enum Value { - UNKNOWN = 0, - V1 = 1, - V2 = 2, - // Version is only allocated 3 bits in the BLEAdvertisement, so this can - // never go beyond V7. - }; - }; - - // Versions of the BLESocket. - struct SocketVersion { - enum Value { - UNKNOWN = 0, - V1 = 1, - V2 = 2, - // SocketVersion is only allocated 3 bits in the BLEAdvertisement, so this - // can never go beyond V7. - }; - }; - - static ConstPtr fromBytes( - ConstPtr ble_advertisement_bytes); - - static ConstPtr toBytes(Version::Value version, - SocketVersion::Value socket_version, - ConstPtr service_id_hash, - ConstPtr data); - - static const std::uint32_t kServiceIdHashLength; - - ~BLEAdvertisement(); - - Version::Value getVersion() const; - SocketVersion::Value getSocketVersion() const; - ConstPtr getServiceIdHash() const; - ConstPtr getData() const; - - // Operator overloads when comparing ConstPtr. - bool operator==(const BLEAdvertisement &rhs) const; - bool operator<(const BLEAdvertisement &rhs) const; - - private: - static bool isSupportedVersion(Version::Value version); - static bool isSupportedSocketVersion(SocketVersion::Value socket_version); - static Version::Value parseVersionFromByte(std::uint16_t byte); - static SocketVersion::Value parseSocketVersionFromByte(std::uint16_t byte); - static size_t deserializeDataSize(const char *data_size_bytes_read_ptr); - static size_t computeDataSize(ConstPtr ble_advertisement_bytes); - static size_t computeAdvertisementLength(ConstPtr data); - static void serializeVersionByte(char *version_byte_write_ptr, - Version::Value version); - static void serializeSocketVersionByte(char *socket_version_byte_write_ptr, - SocketVersion::Value socket_version); - static void serializeDataSize(char *data_size_bytes_write_ptr, - size_t data_size); - - static const std::uint32_t kVersionLength; - static const std::uint32_t kDataSizeLength; - static const std::uint32_t kMinAdvertisementLength; - static const std::uint32_t kMaxDataSize; - static const std::uint16_t kVersionBitmask; - static const std::uint16_t kSocketVersionBitmask; - - BLEAdvertisement(Version::Value version, SocketVersion::Value socket_version, - ConstPtr service_id_hash, - ConstPtr data); - - const Version::Value version_; - const SocketVersion::Value socket_version_; - ScopedPtr > service_id_hash_; - ScopedPtr > data_; -}; - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_INTERNAL_MEDIUMS_BLE_ADVERTISEMENT_H_ diff --git a/cpp/core/internal/mediums/ble_advertisement_header.cc b/cpp/core/internal/mediums/ble_advertisement_header.cc deleted file mode 100644 index e433877d..00000000 --- a/cpp/core/internal/mediums/ble_advertisement_header.cc +++ /dev/null @@ -1,208 +0,0 @@ -#include "core/internal/mediums/ble_advertisement_header.h" - -#include "platform/base64_utils.h" -#include "platform/byte_array.h" -#include "platform/logging.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -// The following IfThisThenThat is for BloomFilter length in -// ble_v2.createAdvertisementHeader -// LINT.IfChange -const std::uint32_t BLEAdvertisementHeader::kServiceIdBloomFilterLength = 10; -// LINT.ThenChange(//depot/google3/core/internal/\ -// mediums/ble_v2.h) -const std::uint32_t BLEAdvertisementHeader::kAdvertisementHashLength = 4; - -const std::uint32_t BLEAdvertisementHeader::kVersionAndNumSlotsLength = 1; -const std::uint32_t BLEAdvertisementHeader::kMinAdvertisementHeaderLength = - kVersionAndNumSlotsLength + kServiceIdBloomFilterLength + - kAdvertisementHashLength; -const std::uint16_t BLEAdvertisementHeader::kVersionBitmask = 0x0E0; -const std::uint16_t BLEAdvertisementHeader::kNumSlotsBitmask = 0x01F; - -ConstPtr BLEAdvertisementHeader::fromString( - const std::string &ble_advertisement_header_string) { - ScopedPtr > scoped_ble_advertisement_header_bytes( - Base64Utils::decode(ble_advertisement_header_string)); - if (scoped_ble_advertisement_header_bytes.isNull()) { - NEARBY_LOG( - INFO, - "Cannot deserialize BLEAdvertisementHeader: failed Base64 decoding"); - return ConstPtr(); - } - - if (scoped_ble_advertisement_header_bytes->size() < - kMinAdvertisementHeaderLength) { - NEARBY_LOG(INFO, - "Cannot deserialize BLEAdvertisementHeader: expecting min %u " - "raw bytes, got %zu instead", - kMinAdvertisementHeaderLength, - scoped_ble_advertisement_header_bytes->size()); - return ConstPtr(); - } - - // Now, time to read the bytes! - const char *ble_advertisement_header_read_ptr = - scoped_ble_advertisement_header_bytes->getData(); - - // 1. Version. - // The first 3 bits of the first byte represent the version. - Version::Value version = parseVersionFromByte( - static_cast(*ble_advertisement_header_read_ptr)); - if (version != Version::V2) { - NEARBY_LOG( - INFO, - "Cannot deserialize BLEAdvertisementHeader, unsupported version %u", - version); - return ConstPtr(); - } - - // 2. Number of slots. - // The last 5 bits of the first byte represent the number of slots. - std::uint32_t num_slots = parseNumSlotsFromByte( - static_cast(*ble_advertisement_header_read_ptr)); - ble_advertisement_header_read_ptr += kVersionAndNumSlotsLength; - - // 3. Service ID bloom filter. - ScopedPtr > scoped_service_id_bloom_filter( - MakeConstPtr(new ByteArray(ble_advertisement_header_read_ptr, - kServiceIdBloomFilterLength))); - ble_advertisement_header_read_ptr += kServiceIdBloomFilterLength; - - // 4. Advertisement hash. - ScopedPtr > scoped_advertisement_hash( - MakeConstPtr(new ByteArray(ble_advertisement_header_read_ptr, - kAdvertisementHashLength))); - ble_advertisement_header_read_ptr += kAdvertisementHashLength; - - return MakeRefCountedConstPtr(new BLEAdvertisementHeader( - version, num_slots, scoped_service_id_bloom_filter.release(), - scoped_advertisement_hash.release())); -} - -std::string BLEAdvertisementHeader::asString( - Version::Value version, std::uint32_t num_slots, - ConstPtr service_id_bloom_filter, - ConstPtr advertisement_hash) { - // Check that the given input is valid. - if (version != Version::V2) { - NEARBY_LOG( - INFO, "Cannot serialize BLEAdvertisementHeader: unsupported Version %u", - version); - return ""; - } - - if (service_id_bloom_filter->size() != kServiceIdBloomFilterLength) { - NEARBY_LOG(INFO, - "Cannot serialize BLEAdvertisementHeader: expected " - "service_id_bloom_filter of %u bytes, but got %zu", - kServiceIdBloomFilterLength, service_id_bloom_filter->size()); - return ""; - } - - if (advertisement_hash->size() != kAdvertisementHashLength) { - NEARBY_LOG(INFO, - "Cannot serialize BLEAdvertisementHeader: expected " - "advertisement_hash of %u bytes, but got %zu", - kAdvertisementHashLength, advertisement_hash->size()); - return ""; - } - - // Initialize the bytes. - ByteArray advertisement_header_bytes{kMinAdvertisementHeaderLength}; - char *advertisement_header_bytes_write_ptr = - advertisement_header_bytes.getData(); - - // 1. Version. - serializeVersionByte(advertisement_header_bytes_write_ptr, version); - - // 2. Number of slots. - serializeNumSlots(advertisement_header_bytes_write_ptr, num_slots); - advertisement_header_bytes_write_ptr += kVersionAndNumSlotsLength; - - // 3. Service ID bloom filter. - memcpy(advertisement_header_bytes_write_ptr, - service_id_bloom_filter->getData(), kServiceIdBloomFilterLength); - advertisement_header_bytes_write_ptr += kServiceIdBloomFilterLength; - - // 4. Advertisement hash. - memcpy(advertisement_header_bytes_write_ptr, advertisement_hash->getData(), - kAdvertisementHashLength); - advertisement_header_bytes_write_ptr += kAdvertisementHashLength; - - // Header needs to be binary safe, so apply a Base64 encoding. - return Base64Utils::encode(advertisement_header_bytes); -} - -BLEAdvertisementHeader::Version::Value -BLEAdvertisementHeader::parseVersionFromByte(std::uint16_t byte) { - return static_cast((byte & kVersionBitmask) >> 5); -} - -std::uint32_t BLEAdvertisementHeader::parseNumSlotsFromByte( - std::uint16_t byte) { - return static_cast((byte & kNumSlotsBitmask)); -} - -void BLEAdvertisementHeader::serializeVersionByte(char *version_byte_write_ptr, - Version::Value version) { - *version_byte_write_ptr |= - static_cast((version << 5) & kVersionBitmask); -} - -void BLEAdvertisementHeader::serializeNumSlots(char *num_slots_byte_write_ptr, - std::uint32_t num_slots) { - *num_slots_byte_write_ptr |= static_cast(num_slots & kNumSlotsBitmask); -} - -BLEAdvertisementHeader::BLEAdvertisementHeader( - BLEAdvertisementHeader::Version::Value version, std::uint32_t num_slots, - ConstPtr service_id_bloom_filter, - ConstPtr advertisement_hash) - : version_(version), - num_slots_(num_slots), - service_id_bloom_filter_(service_id_bloom_filter), - advertisement_hash_(advertisement_hash) {} - -BLEAdvertisementHeader::~BLEAdvertisementHeader() { - // Nothing to do. -} - -BLEAdvertisementHeader::Version::Value BLEAdvertisementHeader::getVersion() - const { - return version_; -} - -std::uint32_t BLEAdvertisementHeader::getNumSlots() const { return num_slots_; } - -ConstPtr BLEAdvertisementHeader::getServiceIdBloomFilter() const { - return service_id_bloom_filter_.get(); -} - -ConstPtr BLEAdvertisementHeader::getAdvertisementHash() const { - return advertisement_hash_.get(); -} - -bool BLEAdvertisementHeader::operator<( - const BLEAdvertisementHeader &rhs) const { - if (this->getVersion() != rhs.getVersion()) { - return this->getVersion() < rhs.getVersion(); - } - if (this->getNumSlots() != rhs.getNumSlots()) { - return this->getNumSlots() < rhs.getNumSlots(); - } - if (*(this->getServiceIdBloomFilter()) != *(rhs.getServiceIdBloomFilter())) { - return *(this->getServiceIdBloomFilter()) < - *(rhs.getServiceIdBloomFilter()); - } - return *(this->getAdvertisementHash()) < *(rhs.getAdvertisementHash()); -} - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core/internal/mediums/ble_advertisement_header.h b/cpp/core/internal/mediums/ble_advertisement_header.h deleted file mode 100644 index 3cf70e5a..00000000 --- a/cpp/core/internal/mediums/ble_advertisement_header.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef CORE_INTERNAL_MEDIUMS_BLE_ADVERTISEMENT_HEADER_H_ -#define CORE_INTERNAL_MEDIUMS_BLE_ADVERTISEMENT_HEADER_H_ - -#include "platform/byte_array.h" -#include "platform/ptr.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -// Represents the format of the Mediums BLE Advertisement Header used in -// Advertising + Discovery. -// -// [VERSION][NUM_SLOTS][SERVICE_ID_BLOOM_FILTER][ADVERTISEMENT_HASH] -// -// See go/nearby-ble-design for more information. -class BLEAdvertisementHeader { - public: - // Versions of the BLEAdvertisementHeader. - struct Version { - enum Value { - V2 = 2, - // Version is only allocated 3 bits in the BLEAdvertisementHeader, so this - // can never go beyond V7. - // - // V1 is not present because it's an old format used in Nearby Connections - // before this logic was pushed down into Nearby Mediums. V1 put - // everything in the service data, while V2 puts the data inside a GATT - // characteristic so the two are not compatible. - }; - }; - - static ConstPtr fromString( - const std::string &ble_advertisement_header_string); - - static std::string asString(Version::Value version, std::uint32_t num_slots, - ConstPtr service_id_bloom_filter, - ConstPtr advertisement_hash); - - static const std::uint32_t kServiceIdBloomFilterLength; - static const std::uint32_t kAdvertisementHashLength; - - ~BLEAdvertisementHeader(); - - Version::Value getVersion() const; - std::uint32_t getNumSlots() const; - ConstPtr getServiceIdBloomFilter() const; - ConstPtr getAdvertisementHash() const; - - // Operator overloads when comparing ConstPtr. - bool operator<(const BLEAdvertisementHeader &rhs) const; - - private: - // DiscoveredPeripheralTracker needs to be a friend of this class because it - // directly calls the constructor (the Java code keeps the constructor package - // private). - // Calling the constuctor directly allows us to avoid the unnessary extra - // calls to parse and decode to get the BLEAdvertisementHeader. - template - friend class DiscoveredPeripheralTracker; - - static Version::Value parseVersionFromByte(std::uint16_t byte); - static std::uint32_t parseNumSlotsFromByte(std::uint16_t byte); - - static const std::uint32_t kVersionAndNumSlotsLength; - static const std::uint32_t kMinAdvertisementHeaderLength; - static const std::uint16_t kVersionBitmask; - static const std::uint16_t kNumSlotsBitmask; - - BLEAdvertisementHeader(Version::Value version, std::uint32_t num_slots, - ConstPtr service_id_bloom_filter, - ConstPtr advertisement_hash); - - static void serializeVersionByte(char *version_byte_write_ptr, - Version::Value version); - static void serializeNumSlots(char *num_slots_byte_write_ptr, - std::uint32_t num_slots); - - const Version::Value version_; - const uint32_t num_slots_; - ScopedPtr > service_id_bloom_filter_; - ScopedPtr > advertisement_hash_; -}; - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_INTERNAL_MEDIUMS_BLE_ADVERTISEMENT_HEADER_H_ diff --git a/cpp/core/internal/mediums/ble_advertisement_header_test.cc b/cpp/core/internal/mediums/ble_advertisement_header_test.cc deleted file mode 100644 index df9267c6..00000000 --- a/cpp/core/internal/mediums/ble_advertisement_header_test.cc +++ /dev/null @@ -1,221 +0,0 @@ -#include "core/internal/mediums/ble_advertisement_header.h" - -#include "platform/base64_utils.h" -#include "gtest/gtest.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -const BLEAdvertisementHeader::Version::Value kVersion = - BLEAdvertisementHeader::Version::V2; -const std::uint32_t kNumSlots = 2; -const char kServiceIDBloomFilter[] = {0x01, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x08, 0x09, 0x0A}; -const char kAdvertisementHash[] = {0x0A, 0x0B, 0x0C, 0x0D}; -const size_t kAdvertisementHeaderLength = 15; -const size_t kLongAdvertisementHeaderLength = kAdvertisementHeaderLength + 1; -const size_t kShortAdvertisementHeaderLength = kAdvertisementHeaderLength - 1; - -TEST(BLEAdvertisementHeader, SerializationDeserializationWorks) { - ScopedPtr > scoped_service_id_bloom_filter(MakeConstPtr( - new ByteArray(kServiceIDBloomFilter, - sizeof(kServiceIDBloomFilter) / sizeof(char)))); - ScopedPtr > scoped_advertisement_hash( - MakeConstPtr(new ByteArray(kAdvertisementHash, - sizeof(kAdvertisementHash) / sizeof(char)))); - - std::string ble_advertisement_header_string(BLEAdvertisementHeader::asString( - kVersion, kNumSlots, scoped_service_id_bloom_filter.get(), - scoped_advertisement_hash.get())); - ScopedPtr > scoped_ble_advertisement_header( - BLEAdvertisementHeader::fromString(ble_advertisement_header_string)); - - ASSERT_EQ(kVersion, scoped_ble_advertisement_header->getVersion()); - ASSERT_EQ(kNumSlots, scoped_ble_advertisement_header->getNumSlots()); - ASSERT_EQ( - 0, - memcmp( - kServiceIDBloomFilter, - scoped_ble_advertisement_header->getServiceIdBloomFilter()->getData(), - scoped_ble_advertisement_header->getServiceIdBloomFilter()->size())); - ASSERT_EQ( - 0, - memcmp(kAdvertisementHash, - scoped_ble_advertisement_header->getAdvertisementHash()->getData(), - scoped_ble_advertisement_header->getAdvertisementHash()->size())); -} - -TEST(BLEAdvertisementHeader, SerializationFailsWithBadVersion) { - BLEAdvertisementHeader::Version::Value bad_version = - static_cast(666); - - ScopedPtr > scoped_service_id_bloom_filter(MakeConstPtr( - new ByteArray(kServiceIDBloomFilter, - sizeof(kServiceIDBloomFilter) / sizeof(char)))); - ScopedPtr > scoped_advertisement_hash( - MakeConstPtr(new ByteArray(kAdvertisementHash, - sizeof(kAdvertisementHash) / sizeof(char)))); - - std::string ble_advertisement_header_string(BLEAdvertisementHeader::asString( - bad_version, kNumSlots, scoped_service_id_bloom_filter.get(), - scoped_advertisement_hash.get())); - - ASSERT_EQ("", ble_advertisement_header_string); -} - -TEST(BLEAdvertisementHeader, SerializationFailsWithShortServiceIdBloomFilter) { - char short_service_id_bloom_filter[] = {0x01, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x08, 0x09}; - - ScopedPtr > scoped_service_id_bloom_filter(MakeConstPtr( - new ByteArray(short_service_id_bloom_filter, - sizeof(short_service_id_bloom_filter) / sizeof(char)))); - ScopedPtr > scoped_advertisement_hash( - MakeConstPtr(new ByteArray(kAdvertisementHash, - sizeof(kAdvertisementHash) / sizeof(char)))); - - std::string ble_advertisement_header_string(BLEAdvertisementHeader::asString( - kVersion, kNumSlots, scoped_service_id_bloom_filter.get(), - scoped_advertisement_hash.get())); - - ASSERT_EQ("", ble_advertisement_header_string); -} - -TEST(BLEAdvertisementHeader, SerializationFailsWithLongServiceIdBloomFilter) { - char long_service_id_bloom_filter[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x09, 0x0A, 0x0B}; - - ScopedPtr > scoped_service_id_bloom_filter(MakeConstPtr( - new ByteArray(long_service_id_bloom_filter, - sizeof(long_service_id_bloom_filter) / sizeof(char)))); - ScopedPtr > scoped_advertisement_hash( - MakeConstPtr(new ByteArray(kAdvertisementHash, - sizeof(kAdvertisementHash) / sizeof(char)))); - - std::string ble_advertisement_header_string(BLEAdvertisementHeader::asString( - kVersion, kNumSlots, scoped_service_id_bloom_filter.get(), - scoped_advertisement_hash.get())); - - ASSERT_EQ("", ble_advertisement_header_string); -} - -TEST(BLEAdvertisementHeader, SerializationFailsWithShortAdvertisementHash) { - char short_advertisement_hash[] = {0x0A, 0x0B, 0x0C}; - - ScopedPtr > scoped_service_id_bloom_filter(MakeConstPtr( - new ByteArray(kServiceIDBloomFilter, - sizeof(kServiceIDBloomFilter) / sizeof(char)))); - ScopedPtr > scoped_advertisement_hash(MakeConstPtr( - new ByteArray(short_advertisement_hash, - sizeof(short_advertisement_hash) / sizeof(char)))); - - std::string ble_advertisement_header_string(BLEAdvertisementHeader::asString( - kVersion, kNumSlots, scoped_service_id_bloom_filter.get(), - scoped_advertisement_hash.get())); - - ASSERT_EQ("", ble_advertisement_header_string); -} - -TEST(BLEAdvertisementHeader, SerializationFailsWithLongAdvertisementHash) { - char long_advertisement_hash[] = {0x0A, 0x0B, 0x0C, 0x0D, 0x0E}; - - ScopedPtr > scoped_service_id_bloom_filter(MakeConstPtr( - new ByteArray(kServiceIDBloomFilter, - sizeof(kServiceIDBloomFilter) / sizeof(char)))); - ScopedPtr > scoped_advertisement_hash(MakeConstPtr( - new ByteArray(long_advertisement_hash, - sizeof(long_advertisement_hash) / sizeof(char)))); - - std::string ble_advertisement_header_string(BLEAdvertisementHeader::asString( - kVersion, kNumSlots, scoped_service_id_bloom_filter.get(), - scoped_advertisement_hash.get())); - - ASSERT_EQ("", ble_advertisement_header_string); -} - -TEST(BLEAdvertisementHeader, DeserializationWorksWithExtraBytes) { - ScopedPtr > scoped_service_id_bloom_filter(MakeConstPtr( - new ByteArray(kServiceIDBloomFilter, - sizeof(kServiceIDBloomFilter) / sizeof(char)))); - ScopedPtr > scoped_advertisement_hash( - MakeConstPtr(new ByteArray(kAdvertisementHash, - sizeof(kAdvertisementHash) / sizeof(char)))); - std::string ble_advertisement_header_string = - BLEAdvertisementHeader::asString(kVersion, kNumSlots, - scoped_service_id_bloom_filter.get(), - scoped_advertisement_hash.get()); - - // Base64 decode the string, add a character, and then re-encode it. We must - // explicitly define how long our array is because we can't use variable - // length arrays. - ScopedPtr > scoped_ble_advertisement_header_bytes( - Base64Utils::decode(ble_advertisement_header_string)); - char raw_long_ble_advertisement_header_bytes[kLongAdvertisementHeaderLength]; - memcpy(raw_long_ble_advertisement_header_bytes, - scoped_ble_advertisement_header_bytes->getData(), - kLongAdvertisementHeaderLength); - ScopedPtr > scoped_long_ble_advertisement_header_bytes( - MakeConstPtr(new ByteArray(raw_long_ble_advertisement_header_bytes, - kLongAdvertisementHeaderLength))); - std::string long_ble_advertisement_header_string = - Base64Utils::encode(scoped_long_ble_advertisement_header_bytes.get()); - - ScopedPtr > scoped_ble_advertisement_header( - BLEAdvertisementHeader::fromString(long_ble_advertisement_header_string)); - - ASSERT_EQ(kVersion, scoped_ble_advertisement_header->getVersion()); - ASSERT_EQ(kNumSlots, scoped_ble_advertisement_header->getNumSlots()); - ASSERT_EQ( - 0, - memcmp( - kServiceIDBloomFilter, - scoped_ble_advertisement_header->getServiceIdBloomFilter()->getData(), - scoped_ble_advertisement_header->getServiceIdBloomFilter()->size())); - ASSERT_EQ( - 0, - memcmp(kAdvertisementHash, - scoped_ble_advertisement_header->getAdvertisementHash()->getData(), - scoped_ble_advertisement_header->getAdvertisementHash()->size())); -} - -TEST(BLEAdvertisementHeader, DeserializationFailsWithShortLength) { - ScopedPtr > scoped_service_id_bloom_filter(MakeConstPtr( - new ByteArray(kServiceIDBloomFilter, - sizeof(kServiceIDBloomFilter) / sizeof(char)))); - ScopedPtr > scoped_advertisement_hash( - MakeConstPtr(new ByteArray(kAdvertisementHash, - sizeof(kAdvertisementHash) / sizeof(char)))); - std::string ble_advertisement_header_string = - BLEAdvertisementHeader::asString(kVersion, kNumSlots, - scoped_service_id_bloom_filter.get(), - scoped_advertisement_hash.get()); - - // Base64 decode the string, remove a character, and then re-encode it. We - // must explicitly define how long our array is because we can't use variable - // length arrays. - ScopedPtr > scoped_ble_advertisement_header_bytes( - Base64Utils::decode(ble_advertisement_header_string)); - char - raw_short_ble_advertisement_header_bytes[kShortAdvertisementHeaderLength]; - memcpy(raw_short_ble_advertisement_header_bytes, - scoped_ble_advertisement_header_bytes->getData(), - kShortAdvertisementHeaderLength); - ScopedPtr > scoped_short_ble_advertisement_header_bytes( - MakeConstPtr(new ByteArray(raw_short_ble_advertisement_header_bytes, - kShortAdvertisementHeaderLength))); - std::string short_ble_advertisement_header_string = - Base64Utils::encode(scoped_short_ble_advertisement_header_bytes.get()); - - ScopedPtr > scoped_ble_advertisement_header( - BLEAdvertisementHeader::fromString( - short_ble_advertisement_header_string)); - - ASSERT_TRUE(scoped_ble_advertisement_header.isNull()); -} - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core/internal/mediums/ble_advertisement_test.cc b/cpp/core/internal/mediums/ble_advertisement_test.cc deleted file mode 100644 index 965cd543..00000000 --- a/cpp/core/internal/mediums/ble_advertisement_test.cc +++ /dev/null @@ -1,322 +0,0 @@ -#include "core/internal/mediums/ble_advertisement.h" - -#include - -#include "gtest/gtest.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { -namespace { - -const BLEAdvertisement::Version::Value kVersion = BLEAdvertisement::Version::V2; -const BLEAdvertisement::SocketVersion::Value kSocketVersion = - BLEAdvertisement::SocketVersion::V2; -const char kServiceIDHashBytes[] = {0x0A, 0x0B, 0x0C}; -const char kData[] = - "How much wood can a woodchuck chuck if a wood chuck would chuck wood?"; -// This corresponds to the length of a specific BLEAdvertisement packed with the -// kData given above. Be sure to update this if kData ever changes. -const size_t kAdvertisementLength = 77; -const size_t kLongAdvertisementLength = kAdvertisementLength + 1000; - -TEST(BLEAdvertisementTest, SerializationDeserializationWorksV1) { - ScopedPtr > scoped_service_id_hash( - MakeConstPtr(new ByteArray(kServiceIDHashBytes, - sizeof(kServiceIDHashBytes) / sizeof(char)))); - ScopedPtr > scoped_data( - MakeConstPtr(new ByteArray(kData, sizeof(kData) / sizeof(char)))); - - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes( - BLEAdvertisement::Version::V1, BLEAdvertisement::SocketVersion::V1, - scoped_service_id_hash.get(), scoped_data.get())); - ScopedPtr > scoped_ble_advertisement( - BLEAdvertisement::fromBytes(scoped_ble_advertisement_bytes.get())); - - ASSERT_EQ(BLEAdvertisement::Version::V1, - scoped_ble_advertisement->getVersion()); - ASSERT_EQ(BLEAdvertisement::SocketVersion::V1, - scoped_ble_advertisement->getSocketVersion()); - ASSERT_EQ(scoped_service_id_hash->size(), - scoped_ble_advertisement->getServiceIdHash()->size()); - ASSERT_EQ(0, memcmp(kServiceIDHashBytes, - scoped_ble_advertisement->getServiceIdHash()->getData(), - scoped_ble_advertisement->getServiceIdHash()->size())); - ASSERT_EQ(scoped_data->size(), scoped_ble_advertisement->getData()->size()); - ASSERT_EQ(0, memcmp(kData, scoped_ble_advertisement->getData()->getData(), - scoped_ble_advertisement->getData()->size())); -} - -TEST(BLEAdvertisementTest, SerializationDeserializationWorks) { - ScopedPtr > scoped_service_id_hash( - MakeConstPtr(new ByteArray(kServiceIDHashBytes, - sizeof(kServiceIDHashBytes) / sizeof(char)))); - ScopedPtr > scoped_data( - MakeConstPtr(new ByteArray(kData, sizeof(kData) / sizeof(char)))); - - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes(kVersion, kSocketVersion, - scoped_service_id_hash.get(), - scoped_data.get())); - ScopedPtr > scoped_ble_advertisement( - BLEAdvertisement::fromBytes(scoped_ble_advertisement_bytes.get())); - - ASSERT_EQ(kVersion, scoped_ble_advertisement->getVersion()); - ASSERT_EQ(kSocketVersion, scoped_ble_advertisement->getSocketVersion()); - ASSERT_EQ(scoped_service_id_hash->size(), - scoped_ble_advertisement->getServiceIdHash()->size()); - ASSERT_EQ(0, memcmp(kServiceIDHashBytes, - scoped_ble_advertisement->getServiceIdHash()->getData(), - scoped_ble_advertisement->getServiceIdHash()->size())); - ASSERT_EQ(scoped_data->size(), scoped_ble_advertisement->getData()->size()); - ASSERT_EQ(0, memcmp(kData, scoped_ble_advertisement->getData()->getData(), - scoped_ble_advertisement->getData()->size())); -} - -TEST(BLEAdvertisementTest, SerializationDeserializationWorksWithEmptyData) { - char empty_data[0]; - - ScopedPtr > scoped_service_id_hash( - MakeConstPtr(new ByteArray(kServiceIDHashBytes, - sizeof(kServiceIDHashBytes) / sizeof(char)))); - ScopedPtr > scoped_data(MakeConstPtr( - new ByteArray(empty_data, sizeof(empty_data) / sizeof(char)))); - - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes(kVersion, kSocketVersion, - scoped_service_id_hash.get(), - scoped_data.get())); - ScopedPtr > scoped_ble_advertisement( - BLEAdvertisement::fromBytes(scoped_ble_advertisement_bytes.get())); - - ASSERT_EQ(kVersion, scoped_ble_advertisement->getVersion()); - ASSERT_EQ(kSocketVersion, scoped_ble_advertisement->getSocketVersion()); - ASSERT_EQ(scoped_service_id_hash->size(), - scoped_ble_advertisement->getServiceIdHash()->size()); - ASSERT_EQ(0, memcmp(kServiceIDHashBytes, - scoped_ble_advertisement->getServiceIdHash()->getData(), - scoped_ble_advertisement->getServiceIdHash()->size())); - ASSERT_EQ(scoped_data->size(), scoped_ble_advertisement->getData()->size()); - ASSERT_EQ(0, memcmp(kData, scoped_ble_advertisement->getData()->getData(), - scoped_ble_advertisement->getData()->size())); -} - -TEST(BLEAdvertisementTest, SerializationDeserializationFailsWithLargeData) { - // Create data that's larger than the allowed size. - char large_data[513]; - - ScopedPtr > scoped_service_id_hash( - MakeConstPtr(new ByteArray(kServiceIDHashBytes, - sizeof(kServiceIDHashBytes) / sizeof(char)))); - ScopedPtr > scoped_data(MakeConstPtr( - new ByteArray(large_data, sizeof(large_data) / sizeof(char)))); - - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes(kVersion, kSocketVersion, - scoped_service_id_hash.get(), - scoped_data.get())); - ScopedPtr > scoped_ble_advertisement( - BLEAdvertisement::fromBytes(scoped_ble_advertisement_bytes.get())); - - ASSERT_TRUE(scoped_ble_advertisement.isNull()); -} - -TEST(BLEAdvertisementTest, SerializationFailsWithBadVersion) { - BLEAdvertisement::Version::Value bad_version = - static_cast(666); - - ScopedPtr > scoped_service_id_hash( - MakeConstPtr(new ByteArray(kServiceIDHashBytes, - sizeof(kServiceIDHashBytes) / sizeof(char)))); - ScopedPtr > scoped_data( - MakeConstPtr(new ByteArray(kData, sizeof(kData) / sizeof(char)))); - - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes(bad_version, kSocketVersion, - scoped_service_id_hash.get(), - scoped_data.get())); - - ASSERT_TRUE(scoped_ble_advertisement_bytes.isNull()); -} - -TEST(BLEAdvertisementTest, SerializationFailsWithBadSocketVersion) { - BLEAdvertisement::SocketVersion::Value bad_socket_version = - static_cast(666); - - ScopedPtr > scoped_service_id_hash( - MakeConstPtr(new ByteArray(kServiceIDHashBytes, - sizeof(kServiceIDHashBytes) / sizeof(char)))); - ScopedPtr > scoped_data( - MakeConstPtr(new ByteArray(kData, sizeof(kData) / sizeof(char)))); - - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes(kVersion, bad_socket_version, - scoped_service_id_hash.get(), - scoped_data.get())); - - ASSERT_TRUE(scoped_ble_advertisement_bytes.isNull()); -} - -TEST(BLEAdvertisementTest, SerializationFailsWithShortServiceIdHash) { - char short_service_id_hash_bytes[] = {0x0A, 0x0B}; - - ScopedPtr > scoped_service_id_hash(MakeConstPtr( - new ByteArray(short_service_id_hash_bytes, - sizeof(short_service_id_hash_bytes) / sizeof(char)))); - ScopedPtr > scoped_data( - MakeConstPtr(new ByteArray(kData, sizeof(kData) / sizeof(char)))); - - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes(kVersion, kSocketVersion, - scoped_service_id_hash.get(), - scoped_data.get())); - - ASSERT_TRUE(scoped_ble_advertisement_bytes.isNull()); -} - -TEST(BLEAdvertisementTest, SerializationFailsWithLongServiceIdHash) { - char long_service_id_hash_bytes[] = {0x0A, 0x0B, 0x0C, 0x0D}; - - ScopedPtr > scoped_service_id_hash(MakeConstPtr( - new ByteArray(long_service_id_hash_bytes, - sizeof(long_service_id_hash_bytes) / sizeof(char)))); - ScopedPtr > scoped_data( - MakeConstPtr(new ByteArray(kData, sizeof(kData) / sizeof(char)))); - - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes(kVersion, kSocketVersion, - scoped_service_id_hash.get(), - scoped_data.get())); - - ASSERT_TRUE(scoped_ble_advertisement_bytes.isNull()); -} - -TEST(BLEAdvertisementTest, SerializationFailsWithLongData) { - // BLEAdvertisement shouldn't be able to support data with the max GATT - // attribute length because it needs some room for the preceding fields. - char long_data[512]; - - ScopedPtr > scoped_service_id_hash( - MakeConstPtr(new ByteArray(kServiceIDHashBytes, - sizeof(kServiceIDHashBytes) / sizeof(char)))); - ScopedPtr > scoped_data( - MakeConstPtr(new ByteArray(long_data, sizeof(long_data) / sizeof(char)))); - - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes(kVersion, kSocketVersion, - scoped_service_id_hash.get(), - scoped_data.get())); - - ASSERT_TRUE(scoped_ble_advertisement_bytes.isNull()); -} - -TEST(BLEAdvertisementTest, DeserializationWorksWithExtraBytes) { - ScopedPtr > scoped_service_id_hash( - MakeConstPtr(new ByteArray(kServiceIDHashBytes, - sizeof(kServiceIDHashBytes) / sizeof(char)))); - ScopedPtr > scoped_data( - MakeConstPtr(new ByteArray(kData, sizeof(kData) / sizeof(char)))); - - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes(kVersion, kSocketVersion, - scoped_service_id_hash.get(), - scoped_data.get())); - - // Copy the bytes into a new array with extra bytes. We must explicitly - // define how long our array is because we can't use variable length arrays. - char raw_ble_advertisement_bytes[kLongAdvertisementLength] {}; - memcpy(raw_ble_advertisement_bytes, scoped_ble_advertisement_bytes->getData(), - std::min(sizeof(raw_ble_advertisement_bytes), - scoped_ble_advertisement_bytes->size())); - - // Re-parse the BLE advertisement using our extra long advertisement bytes. - ScopedPtr > scoped_long_ble_advertisement_bytes( - MakeConstPtr(new ByteArray(raw_ble_advertisement_bytes, - kLongAdvertisementLength))); - ScopedPtr > scoped_long_ble_advertisement( - BLEAdvertisement::fromBytes(scoped_long_ble_advertisement_bytes.get())); - - ASSERT_EQ(kVersion, scoped_long_ble_advertisement->getVersion()); - ASSERT_EQ(kSocketVersion, scoped_long_ble_advertisement->getSocketVersion()); - ASSERT_EQ(scoped_service_id_hash->size(), - scoped_long_ble_advertisement->getServiceIdHash()->size()); - ASSERT_EQ(0, - memcmp(kServiceIDHashBytes, - scoped_long_ble_advertisement->getServiceIdHash()->getData(), - scoped_long_ble_advertisement->getServiceIdHash()->size())); - ASSERT_EQ(scoped_data->size(), - scoped_long_ble_advertisement->getData()->size()); - ASSERT_EQ(0, - memcmp(kData, scoped_long_ble_advertisement->getData()->getData(), - scoped_long_ble_advertisement->getData()->size())); -} - -TEST(BLEAdvertisementTest, DeserializationFailsWithNullBytes) { - ScopedPtr > scoped_ble_advertisement( - BLEAdvertisement::fromBytes(ConstPtr())); - - ASSERT_TRUE(scoped_ble_advertisement.isNull()); -} - -TEST(BLEAdvertisementTest, DeserializationFailsWithShortLength) { - ScopedPtr > scoped_service_id_hash( - MakeConstPtr(new ByteArray(kServiceIDHashBytes, - sizeof(kServiceIDHashBytes) / sizeof(char)))); - ScopedPtr > scoped_data( - MakeConstPtr(new ByteArray(kData, sizeof(kData) / sizeof(char)))); - - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes(kVersion, kSocketVersion, - scoped_service_id_hash.get(), - scoped_data.get())); - - // Cut off the advertisement so that it's too short. - ScopedPtr > scoped_short_ble_advertisement_bytes( - MakeConstPtr( - new ByteArray(scoped_ble_advertisement_bytes->getData(), 7))); - ScopedPtr > scoped_ble_advertisement( - BLEAdvertisement::fromBytes(scoped_short_ble_advertisement_bytes.get())); - - ASSERT_TRUE(scoped_ble_advertisement.isNull()); -} - -TEST(BLEAdvertisementTest, DeserializationFailsWithInvalidDataLength) { - ScopedPtr > scoped_service_id_hash( - MakeConstPtr(new ByteArray(kServiceIDHashBytes, - sizeof(kServiceIDHashBytes) / sizeof(char)))); - ScopedPtr > scoped_data( - MakeConstPtr(new ByteArray(kData, sizeof(kData) / sizeof(char)))); - - ScopedPtr > scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes(kVersion, kSocketVersion, - scoped_service_id_hash.get(), - scoped_data.get())); - - // Corrupt the DATA_SIZE bits. Start by making a raw copy of the BLE - // advertisement bytes so we can modify it. We must explicitly define how long - // our array is because we can't use variable length arrays. - char raw_ble_advertisement_bytes[kAdvertisementLength]; - memcpy(raw_ble_advertisement_bytes, scoped_ble_advertisement_bytes->getData(), - kAdvertisementLength); - - // The data size field lives in indices 4-7. Corrupt it. - memset(raw_ble_advertisement_bytes + 4, 0xFF, 4); - - // Try to parse the BLE advertisement using our corrupted advertisement bytes. - ScopedPtr > scoped_corrupted_ble_advertisement_bytes( - MakeConstPtr( - new ByteArray(raw_ble_advertisement_bytes, kAdvertisementLength))); - ScopedPtr > scoped_ble_advertisement( - BLEAdvertisement::fromBytes( - scoped_corrupted_ble_advertisement_bytes.get())); - - ASSERT_TRUE(scoped_ble_advertisement.isNull()); -} - -} // namespace -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core/internal/mediums/ble_packet.cc b/cpp/core/internal/mediums/ble_packet.cc deleted file mode 100644 index 3f5fad02..00000000 --- a/cpp/core/internal/mediums/ble_packet.cc +++ /dev/null @@ -1,112 +0,0 @@ -#include "core/internal/mediums/ble_packet.h" - -#include - -#include "platform/logging.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -const std::uint32_t BLEPacket::kServiceIdHashLength = 3; - -const std::uint32_t BLEPacket::kMinPacketLength = kServiceIdHashLength; -const std::uint32_t BLEPacket::kMaxDataSize = - std::numeric_limits::max() - kMinPacketLength; - -ConstPtr BLEPacket::fromBytes(ConstPtr ble_packet_bytes) { - if (ble_packet_bytes.isNull()) { - NEARBY_LOG(INFO, "Cannot deserialize BLEPacket: null bytes passed in"); - return ConstPtr(); - } - - if (ble_packet_bytes->size() < kMinPacketLength) { - NEARBY_LOG( - INFO, - "Cannot deserialize BLEPacket: expecting min %u raw bytes, got %zu", - kMinPacketLength, ble_packet_bytes->size()); - return ConstPtr(); - } - - // Now, time to read the bytes! - const char *ble_packet_bytes_read_ptr = ble_packet_bytes->getData(); - - // 1. Service ID hash. - ScopedPtr > scoped_service_id_hash(MakeConstPtr( - new ByteArray(ble_packet_bytes_read_ptr, kServiceIdHashLength))); - ble_packet_bytes_read_ptr += kServiceIdHashLength; - - // 2. Data. - size_t data_size = computeDataSize(ble_packet_bytes); - ScopedPtr > scoped_data( - MakeConstPtr(new ByteArray(ble_packet_bytes_read_ptr, data_size))); - ble_packet_bytes_read_ptr += data_size; - - return MakeConstPtr( - new BLEPacket(scoped_service_id_hash.release(), scoped_data.release())); -} - -ConstPtr BLEPacket::toBytes(ConstPtr service_id_hash, - ConstPtr data) { - if (service_id_hash->size() != kServiceIdHashLength) { - NEARBY_LOG( - INFO, - "Cannot serialize BLEPacket: expected a service_id_hash of %u bytes, " - "but got %zu", - kServiceIdHashLength, service_id_hash->size()); - return ConstPtr(); - } - - if (data->size() > kMaxDataSize) { - NEARBY_LOG(INFO, - "Cannot serialize BLEPacket: expected data of at most %u bytes, " - "but got %zu", - kMaxDataSize, data->size()); - return ConstPtr(); - } - - // Initialize the bytes. - size_t packet_length = computePacketLength(data); - Ptr packet_bytes{new ByteArray{packet_length}}; - char *packet_bytes_write_ptr = packet_bytes->getData(); - - // 1. Service ID hash. - memcpy(packet_bytes_write_ptr, service_id_hash->getData(), - kServiceIdHashLength); - packet_bytes_write_ptr += kServiceIdHashLength; - - // 2. Data. - memcpy(packet_bytes_write_ptr, data->getData(), data->size()); - packet_bytes_write_ptr += data->size(); - - return ConstifyPtr(packet_bytes); -} - -size_t BLEPacket::computeDataSize(ConstPtr ble_packet_bytes) { - return ble_packet_bytes->size() - kMinPacketLength; -} - -size_t BLEPacket::computePacketLength(ConstPtr data) { - // The packet length is the minimum length + the length of the data. - return kMinPacketLength + data->size(); -} - -BLEPacket::BLEPacket(ConstPtr service_id_hash, - ConstPtr data) - : service_id_hash_(service_id_hash), data_(data) {} - -BLEPacket::~BLEPacket() { - // Nothing to do. -} - -ConstPtr BLEPacket::getServiceIdHash() const { - return service_id_hash_.get(); -} - -ConstPtr BLEPacket::getData() const { return data_.get(); } - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core/internal/mediums/ble_packet.h b/cpp/core/internal/mediums/ble_packet.h deleted file mode 100644 index ec7cf0c7..00000000 --- a/cpp/core/internal/mediums/ble_packet.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef CORE_INTERNAL_MEDIUMS_BLE_PACKET_H_ -#define CORE_INTERNAL_MEDIUMS_BLE_PACKET_H_ - -#include "platform/byte_array.h" -#include "platform/ptr.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -// Represents the format of data sent over BLE sockets. -// -// [SERVICE_ID_HASH][DATA] -// -// See go/nearby-ble-design for more information. -class BLEPacket { - public: - static ConstPtr fromBytes(ConstPtr ble_packet_bytes); - - static ConstPtr toBytes(ConstPtr service_id_hash, - ConstPtr data); - - static const std::uint32_t kServiceIdHashLength; - - ~BLEPacket(); - - ConstPtr getServiceIdHash() const; - ConstPtr getData() const; - - private: - static size_t computeDataSize(ConstPtr ble_packet_bytes); - static size_t computePacketLength(ConstPtr data); - - static const std::uint32_t kMinPacketLength; - static const std::uint32_t kMaxDataSize; - - BLEPacket(ConstPtr service_id_hash, ConstPtr data); - - ScopedPtr > service_id_hash_; - ScopedPtr > data_; -}; - -// Represents the format of data sent over BLE sockets. -// -// [SERVICE_ID_HASH][DATA] -// -// See go/nearby-ble-design for more information. -class BlePacket { - public: - static BlePacket FromBytes(const ByteArray& bytes); - - static ByteArray ToBytes(const ByteArray& service_id_hash, - const ByteArray& data); - - static const uint32_t kServiceIdHashLength; - - ~BlePacket(); - - ByteArray GetServiceIdHash() const; - ByteArray GetData() const; - - private: - static size_t ComputeDataSize(const ByteArray& ble_packet_bytes); - static size_t ComputePacketLength(const ByteArray& data); - - static const uint32_t kMinPacketLength; - static const uint32_t kMaxDataSize; - - BlePacket(const ByteArray& service_id_hash, const ByteArray& data); - - ByteArray service_id_hash_; - ByteArray data_; -}; - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_INTERNAL_MEDIUMS_BLE_PACKET_H_ diff --git a/cpp/core/internal/mediums/ble_packet_test.cc b/cpp/core/internal/mediums/ble_packet_test.cc deleted file mode 100644 index 90c0d06b..00000000 --- a/cpp/core/internal/mediums/ble_packet_test.cc +++ /dev/null @@ -1,108 +0,0 @@ -#include "core/internal/mediums/ble_packet.h" - -#include "gtest/gtest.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -const char kServiceIDHash[] = {0x0A, 0x0B, 0x0C}; -const char kData[] = {0x00, 0x01, 0x02, 0x03, 0x04}; - -TEST(BLEPacket, SerializationDeserializationWorks) { - ScopedPtr > scoped_service_id_hash(MakeConstPtr( - new ByteArray(kServiceIDHash, sizeof(kServiceIDHash) / sizeof(char)))); - ScopedPtr > scoped_data( - MakeConstPtr(new ByteArray(kData, sizeof(kData) / sizeof(char)))); - - ScopedPtr > scoped_ble_packet_bytes( - BLEPacket::toBytes(scoped_service_id_hash.get(), scoped_data.get())); - ScopedPtr > scoped_ble_packet( - BLEPacket::fromBytes(scoped_ble_packet_bytes.get())); - - ASSERT_EQ(0, memcmp(kServiceIDHash, - scoped_ble_packet->getServiceIdHash()->getData(), - scoped_ble_packet->getServiceIdHash()->size())); - ASSERT_EQ(0, memcmp(kData, scoped_ble_packet->getData()->getData(), - scoped_ble_packet->getData()->size())); -} - -TEST(BLEPacket, SerializationDeserializationWorksWithEmptyData) { - char empty_data[] = {}; - - ScopedPtr > scoped_service_id_hash(MakeConstPtr( - new ByteArray(kServiceIDHash, sizeof(kServiceIDHash) / sizeof(char)))); - ScopedPtr > scoped_data(MakeConstPtr( - new ByteArray(empty_data, sizeof(empty_data) / sizeof(char)))); - - ScopedPtr > scoped_ble_packet_bytes( - BLEPacket::toBytes(scoped_service_id_hash.get(), scoped_data.get())); - ScopedPtr > scoped_ble_packet( - BLEPacket::fromBytes(scoped_ble_packet_bytes.get())); - - ASSERT_EQ(0, memcmp(kServiceIDHash, - scoped_ble_packet->getServiceIdHash()->getData(), - scoped_ble_packet->getServiceIdHash()->size())); - ASSERT_EQ(0, memcmp(empty_data, scoped_ble_packet->getData()->getData(), - scoped_ble_packet->getData()->size())); -} - -TEST(BLEPacket, SerializationFailsWithShortServiceIdHash) { - char short_service_id_hash[] = {0x0A, 0x0B}; - - ScopedPtr > scoped_service_id_hash(MakeConstPtr( - new ByteArray(short_service_id_hash, - sizeof(short_service_id_hash) / sizeof(char)))); - ScopedPtr > scoped_data( - MakeConstPtr(new ByteArray(kData, sizeof(kData) / sizeof(char)))); - - ScopedPtr > scoped_ble_packet_bytes( - BLEPacket::toBytes(scoped_service_id_hash.get(), scoped_data.get())); - - ASSERT_TRUE(scoped_ble_packet_bytes.isNull()); -} - -TEST(BLEPacket, SerializationFailsWithLongServiceIdHash) { - char long_service_id_hash[]{0x0A, 0x0B, 0x0C, 0x0D}; - - ScopedPtr > scoped_service_id_hash( - MakeConstPtr(new ByteArray(long_service_id_hash, - sizeof(long_service_id_hash) / sizeof(char)))); - ScopedPtr > scoped_data( - MakeConstPtr(new ByteArray(kData, sizeof(kData) / sizeof(char)))); - - ScopedPtr > scoped_ble_packet_bytes( - BLEPacket::toBytes(scoped_service_id_hash.get(), scoped_data.get())); - - ASSERT_TRUE(scoped_ble_packet_bytes.isNull()); -} - -TEST(BLEPacket, DeserializationFailsWithNullBytes) { - ScopedPtr > scoped_ble_packet( - BLEPacket::fromBytes(ConstPtr())); - - ASSERT_TRUE(scoped_ble_packet.isNull()); -} - -TEST(BLEPacket, DeserializationFailsWithShortLength) { - ScopedPtr > scoped_service_id_hash(MakeConstPtr( - new ByteArray(kServiceIDHash, sizeof(kServiceIDHash) / sizeof(char)))); - ScopedPtr > scoped_data( - MakeConstPtr(new ByteArray(kData, sizeof(kData) / sizeof(char)))); - ScopedPtr > scoped_ble_packet_bytes( - BLEPacket::toBytes(scoped_service_id_hash.get(), scoped_data.get())); - - // Cut off the packet so that it's too short - ScopedPtr > scoped_short_ble_packet_bytes( - MakeConstPtr(new ByteArray(scoped_ble_packet_bytes->getData(), 2))); - ScopedPtr > scoped_ble_packet( - BLEPacket::fromBytes(scoped_short_ble_packet_bytes.get())); - - ASSERT_TRUE(scoped_ble_packet.isNull()); -} - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core/internal/mediums/ble_peripheral.cc b/cpp/core/internal/mediums/ble_peripheral.cc deleted file mode 100644 index ef54ec8c..00000000 --- a/cpp/core/internal/mediums/ble_peripheral.cc +++ /dev/null @@ -1,19 +0,0 @@ -#include "core/internal/mediums/ble_peripheral.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -BLEPeripheral::BLEPeripheral(ConstPtr id) : id_(id) {} - -BLEPeripheral::~BLEPeripheral() { - // Nothing to do. -} - -ConstPtr BLEPeripheral::getId() const { return id_.get(); } - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core/internal/mediums/ble_peripheral.h b/cpp/core/internal/mediums/ble_peripheral.h deleted file mode 100644 index 0c5acd01..00000000 --- a/cpp/core/internal/mediums/ble_peripheral.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef CORE_INTERNAL_MEDIUMS_BLE_PERIPHERAL_H_ -#define CORE_INTERNAL_MEDIUMS_BLE_PERIPHERAL_H_ - -#include "platform/byte_array.h" -#include "platform/ptr.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -class BLEPeripheral { - public: - explicit BLEPeripheral(ConstPtr id); - ~BLEPeripheral(); - - ConstPtr getId() const; - - private: - // A unique identifier for this peripheral. It can be the BLE advertisement it - // was found on, or even simply the BLE MAC address. - ScopedPtr> id_; -}; - - -// Represents BLE peripheral for testing. -class BlePeripheral { - public: - explicit BlePeripheral(const ByteArray& id) : id_(id) {} - ~BlePeripheral() = default; - - const ByteArray& GetId() const { return id_; } - - private: - // A unique identifier for this peripheral. It can be the BLE advertisement it - // was found on, or even simply the BLE MAC address. - const ByteArray id_; -}; - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_INTERNAL_MEDIUMS_BLE_PERIPHERAL_H_ diff --git a/cpp/core_v2/internal/mediums/ble_test.cc b/cpp/core/internal/mediums/ble_test.cc similarity index 95% rename from cpp/core_v2/internal/mediums/ble_test.cc rename to cpp/core/internal/mediums/ble_test.cc index 9977d6ac..d5a9df31 100644 --- a/cpp/core_v2/internal/mediums/ble_test.cc +++ b/cpp/core/internal/mediums/ble_test.cc @@ -1,12 +1,12 @@ -#include "core_v2/internal/mediums/ble.h" +#include "core/internal/mediums/ble.h" #include -#include "core_v2/internal/mediums/bluetooth_radio.h" -#include "platform_v2/base/medium_environment.h" -#include "platform_v2/public/ble.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/logging.h" +#include "core/internal/mediums/bluetooth_radio.h" +#include "platform/base/medium_environment.h" +#include "platform/public/ble.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/logging.h" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/cpp/core/internal/mediums/ble_v2.cc b/cpp/core/internal/mediums/ble_v2.cc deleted file mode 100644 index 4b38ecd4..00000000 --- a/cpp/core/internal/mediums/ble_v2.cc +++ /dev/null @@ -1,826 +0,0 @@ -#include "core/internal/mediums/ble.h" -#include "core/internal/mediums/ble_advertisement_header.h" -#include "core/internal/mediums/bloom_filter.h" -#include "core/internal/mediums/utils.h" -#include "core/internal/mediums/uuid.h" -#include "platform/synchronized.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -namespace ble_v2 { - -template -class ProcessOnLostRunnable : public Runnable { - public: - explicit ProcessOnLostRunnable(Ptr> ble_v2) - : ble_v2_(ble_v2) {} - - void run() override { ble_v2_->processOnLostTimeout(); } - - private: - Ptr> ble_v2_; -}; - -template -class OnAdvertisementFoundRunnable : public Runnable { - public: - OnAdvertisementFoundRunnable( - Ptr> ble_v2, Ptr peripheral, - ConstPtr advertisement_data) - : ble_v2_(ble_v2), - peripheral_(peripheral), - advertisement_data_(advertisement_data) {} - - // This method is synchronized because it affects class state, but is called - // from a separate thread that fires whenever a BLE advertisement is seen. - void run() override { - Synchronized s(ble_v2_->lock_.get()); - - ble_v2_->discovered_peripheral_tracker_->processFoundBleAdvertisement( - peripheral_, advertisement_data_.release(), - MakePtr(new typename BLEV2::GATTAdvertisementFetcherFacade( - ble_v2_))); - } - - private: - Ptr> ble_v2_; - Ptr peripheral_; - ScopedPtr> advertisement_data_; -}; - -} // namespace ble_v2 - -template -const std::int32_t BLEV2::kNumAdvertisementSlots = 2; - -template -const std::int32_t BLEV2::kMaxAdvertisementLength = 512; - -template -const std::int32_t BLEV2::kDummyServiceIdLength = 512; - -template -const char* BLEV2::kCopresenceServiceUuid = - "0000FEF3-0000-1000-8000-00805F9B34FB"; - -template -const std::int64_t BLEV2::kOnLostTimeoutMillis = 15000; - -template -const std::int64_t BLEV2::kGattAdvertisementOperationTimeoutMillis = - 5000; - -template -const std::int64_t - BLEV2::kMinConnectionAttemptRecoveryDurationMillis = 1000; - -template -const std::int32_t - BLEV2::kMaxConnectionAttemptRecoveryFuzzDurationMillis = 10000; - -template -const std::uint32_t BLEV2::kDefaultMtu = 512; - -// These two values make up the base UUID we use when advertising a slot. The -// base is an all zero Version-3 name-based UUID. To turn this into an -// advertisement slot UUID, we simply OR the least significant bits with the -// slot number. -// -// More info about the format can be found here: -// https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions_3_and_5_(namespace_name-based) -template -const std::int64_t BLEV2::kAdvertisementUuidMsb = 0x0000000000003000; - -template -const std::int64_t BLEV2::kAdvertisementUuidLsb = 0x8000000000000000; - -template -BLEV2::BLEV2(Ptr> bluetooth_radio) - : lock_(Platform::createLock()), - platform_thread_offloader_(Platform::createSingleThreadExecutor()), - prng_(MakePtr(new Prng())), - hash_utils_(Platform::createHashUtils()), - bluetooth_radio_(bluetooth_radio), - bluetooth_adapter_(Platform::createBluetoothAdapter()), - ble_medium_(Platform::createBLEMediumV2()), - scanning_info_(), - discovered_peripheral_tracker_( - new DiscoveredPeripheralTracker()), - on_lost_executor_(Platform::createScheduledExecutor()), - advertising_info_(), - gatt_server_info_(), - accepting_connections_info_() {} - -template -BLEV2::~BLEV2() { - Synchronized s(lock_.get()); - - on_lost_executor_->shutdown(); - platform_thread_offloader_->shutdown(); - stopAdvertising(); - stopAdvertisementGattServer(); - stopAcceptingConnections(); - stopScanning(); - // discovered_peripheral_tracker is a ScopedPtr member and will take care of - // itself. -} - -template -bool BLEV2::isAvailable() { - // This is purposefully left un-synchronized like its java counterpart. - // Callers should be able to query this without waiting for other operations - // to complete first and this should be safe to call after shutdown. We would - // have made it static, but it relies on variables from the constructor (like - // ble_medium_ and bluetooth_adapter_). - return !ble_medium_.isNull() && !bluetooth_adapter_.isNull(); -} - -// Returns true if currently scanning for BLE advertisements. -template -bool BLEV2::isAdvertising() { - Synchronized s(lock_.get()); - - return !advertising_info_.isNull(); -} - -// Starts BLE advertising, delivering additional information through a GATT -// server. -template -bool BLEV2::startAdvertising( - const string& service_id, ConstPtr advertisement_bytes, - BLEMediumV2::PowerMode::Value power_mode, - const string& fast_advertisement_service_uuid) { - Synchronized s(lock_.get()); - - // Avoid leaks. - ScopedPtr> scoped_advertisement_bytes( - advertisement_bytes); - - if (service_id.empty() || scoped_advertisement_bytes.isNull()) { - // logger.atSevere().log("Refusing to start BLE advertising because a null - // parameter was passed in."); - return false; - } - - if (scoped_advertisement_bytes->size() > kMaxAdvertisementLength) { - // logger.atSevere().log("Refusing to start BLE advertising because the - // advertisement was too long. Expected at most %d bytes but received %d.", - // kMaxAdvertisementLength, scoped_advertisement_bytes->size()); - return false; - } - - // Note: We don't include logic checking/using the fast_pair_model_id because - // that is a java-only concept for now. - - if (isAdvertising()) { - // logger.atSevere().log("Failed to BLE advertise because we're already - // advertising."); - return false; - } - - if (!bluetooth_radio_->isEnabled()) { - // logger.atSevere().log("Can't start BLE advertising because Bluetooth - // isn't enabled."); - return false; - } - - if (!isAvailable()) { - // logger.atSevere().log("Can't start BLE advertising because BLE is not - // available."); - return false; - } - - // TODO(ahlee): Remove this check here and in the java code (redundant) - // Stop any existing advertisement GATT servers. We don't stop it in - // stopAdvertising() to avoid GATT issues with BLE sockets. - if (isAdvertisementGattServerRunning()) { - stopAdvertisementGattServer(); - } - - // Start a GATT server to deliver the full advertisement data. If we fail to - // advertise the header, we must shut this down before the method returns. - bool is_fast_advertisement = !fast_advertisement_service_uuid.empty(); - if (!is_fast_advertisement) { - if (!startAdvertisementGattServer(service_id, - scoped_advertisement_bytes.get())) { - // logger.atSevere().log("Failed to to BLE advertise because the - // advertisement GATT server failed to start"); - return false; - } - } - - ScopedPtr> advertisement_header_bytes( - createAdvertisementHeader(service_id, scoped_advertisement_bytes.get(), - is_fast_advertisement)); - if (advertisement_header_bytes.isNull()) { - // logger.atSevere().log("Failed to to BLE advertise because we could not - // create an advertisement header"); - // We failed to start BLE advertising, so stop the advertisement GATT - // server. - stopAdvertisementGattServer(); - return false; - } - - ScopedPtr> advertisement( - new BLEAdvertisementData()); - advertisement->is_connectable = true; - advertisement->tx_power_level = - BLEAdvertisementData::UNSPECIFIED_TX_POWER_LEVEL; - - ScopedPtr> scan_response( - new BLEAdvertisementData()); - scan_response->is_connectable = true; - scan_response->tx_power_level = - BLEAdvertisementData::UNSPECIFIED_TX_POWER_LEVEL; - scan_response->service_uuids.insert(kCopresenceServiceUuid); - scan_response->service_data.insert(std::make_pair( - kCopresenceServiceUuid, advertisement_header_bytes.release())); - - // Note: We don't use fast pair data because that is java-only for now. - - // TODO(ahlee): Fix this if check in the java code. - if (is_fast_advertisement) { - ScopedPtr> service_id_hash( - generateServiceIdHash(BLEAdvertisement::Version::V2, service_id)); - ScopedPtr> fast_advertisement_bytes( - BLEAdvertisement::toBytes( - BLEAdvertisement::Version::V2, BLEAdvertisement::SocketVersion::V2, - service_id_hash.get(), scoped_advertisement_bytes.get())); - if (fast_advertisement_bytes.isNull()) { - // logger.atSevere().log("Failed to BLE advertise because we could not - // create a fast advertisement for service UUID %s.", - // fast_advertisement_service_uuid); - - // We shouldn't have started an advertisement GATT server in the first - // place if we are using fast advertisements. However, to avoid careless - // leaks, try shutting down the server anyway. - stopAdvertisementGattServer(); - return false; - } - advertisement->service_data.insert(std::make_pair( - fast_advertisement_service_uuid, fast_advertisement_bytes.release())); - scan_response->service_uuids.insert(fast_advertisement_service_uuid); - } - - if (!ble_medium_->startAdvertising(ConstifyPtr(advertisement.release()), - ConstifyPtr(scan_response.release()), - power_mode)) { - // If BLE advertising was not successful, stop the advertisement GATT - // server. - stopAdvertisementGattServer(); - return false; - } - - // logger.atVerbose().flog("Started BLE advertising with advertisement %s for - // serviceID %s.", advertisement_header, service_id); - advertising_info_ = MakePtr(new AdvertisingInfo(service_id)); - return true; -} - -template -ConstPtr BLEV2::createAdvertisementHeader( - const string& service_id, ConstPtr advertisement_bytes, - bool is_fast_advertisement) { - // Create a randomized dummy service ID to anonymize our header with. - string dummy_service_id; - dummy_service_id.reserve(kDummyServiceIdLength); - for (int i = 0; i < kDummyServiceIdLength; i++) { - dummy_service_id[i] = static_cast(prng_->nextInt32() & 0x000000FF); - } - - // Put the service ID along with the dummy service ID into our bloom filter - // Note: BloomFilter length should always match - // BLEAdvertisementHeader::kServiceIdBloomFilterLength - ScopedPtr>> bloom_filter(new BloomFilter<10>()); - bloom_filter->add(dummy_service_id); - - // Only add the service ID to our bloom filter if it's not a fast - // advertisement. Fast advertisements want discoverers to avoid reading our - // GATT advertisement. - if (!is_fast_advertisement) { - bloom_filter->add(service_id); - } - - // Create a hash seeded from dummy_service_id + advertisementBytes - // - // First, populate advertisement_bodies with the dummy_service_id and - // advertisement_bytes. - string advertisement_bodies; - advertisement_bodies.reserve(dummy_service_id.size() + - advertisement_bytes->size()); - advertisement_bodies.append(dummy_service_id.data(), dummy_service_id.size()); - advertisement_bodies.append(advertisement_bytes->getData(), - advertisement_bytes->size()); - - // Then, generate the advertisement hash from the populated - // advertisement_bodies string. - ScopedPtr> advertisement_bodies_byte_array(MakeConstPtr( - new ByteArray(advertisement_bodies.data(), advertisement_bodies.size()))); - ScopedPtr> advertisement_hash( - generateAdvertisementHash(advertisement_bodies_byte_array.get())); - - ScopedPtr> bloom_filter_bytes(bloom_filter->asBytes()); - string ble_advertisement_header_string = BLEAdvertisementHeader::asString( - BLEAdvertisementHeader::Version::V2, kNumAdvertisementSlots, - bloom_filter_bytes.get(), advertisement_hash.get()); - - return MakeConstPtr(new ByteArray(ble_advertisement_header_string.data(), - ble_advertisement_header_string.size())); -} - -// Stops BLE advertising. -template -void BLEV2::stopAdvertising() { - Synchronized s(lock_.get()); - - if (!isAdvertising()) { - // logger.atDebug().log("Can't turn off BLE advertising because it never - // started."); - return; - } - - ble_medium_->stopAdvertising(); - // Reset advertising_info_to mark that we're no longer advertising. - advertising_info_.destroy(); - - // Do NOT stop the advertisement GATT server here. Doing so will cause any - // other existing GATT connections to stop receiving callbacks. This affects - // our BLE sockets. Therefore, we only stop it in shutdown() and - // startAdvertising(), where it is safe to do so. At those two points, we - // shouldn't expect any BLE sockets to be connected. - - // logger.atVerbose().log("Turned BLE advertising off"); -} - -// Returns true if currently scanning for BLE advertisements. -template -bool BLEV2::isScanning() { - Synchronized s(lock_.get()); - - return !scanning_info_.isNull(); -} - -// Starts scanning for BLE advertisements (if it is possible for the device). -template -bool BLEV2::startScanning( - const string& service_id, - Ptr discovered_peripheral_callback, - BLEMediumV2::PowerMode::Value power_mode, - const string& fast_advertisement_service_uuid) { - Synchronized s(lock_.get()); - - // Avoid leaks. - ScopedPtr> - scoped_discovered_peripheral_callback(discovered_peripheral_callback); - - if (service_id.empty() || scoped_discovered_peripheral_callback.isNull()) { - // logger.atSevere().log("Refusing to start BLE scanning because at least - // one of workSource, serviceId, or discoveredPeripheralCallback is null."); - return false; - } - - if (isScanning()) { - // logger.atSevere().log("Refusing to start BLE scanning because we are - // already scanning."); - return false; - } - - if (!bluetooth_radio_->isEnabled()) { - // logger.atSevere().log("Can't start BLE scanning because Bluetooth was - // never turned on"); - return false; - } - - if (!isAvailable()) { - // logger.atSevere().log("Can't start BLE scanning because BLE is not - // available."); - return false; - } - - discovered_peripheral_tracker_->startTracking( - service_id, scoped_discovered_peripheral_callback.release(), - fast_advertisement_service_uuid); - // Avoid leaks. - ScopedPtr> scan_callback_facade( - new ScanCallbackFacade(self_)); - std::set service_uuids; - service_uuids.insert(kCopresenceServiceUuid); - if (!ble_medium_->startScanning(service_uuids, power_mode, - scan_callback_facade.get())) { - discovered_peripheral_tracker_->stopTracking(service_id); - return false; - } - - // logger.atVerbose().log("Started BLE scanning for serviceID %s.", - // service_id); - scanning_info_ = MakePtr(new ScanningInfo( - service_id, scan_callback_facade.release(), createOnLostAlarm())); - return true; -} - -template -void BLEV2::onAdvertisementFoundImpl( - Ptr ble_peripheral, - ConstPtr advertisement_data) { - offloadFromPlatformThread( - MakePtr(new ble_v2::OnAdvertisementFoundRunnable( - self_, ble_peripheral, advertisement_data))); -} - -// This method is synchronized because it affects class state, but is called -// from a separate thread that has a recurring alarm running on it. -template -void BLEV2::processOnLostTimeout() { - Synchronized s(lock_.get()); - - discovered_peripheral_tracker_->processLostGattAdvertisements(); -} - -// Stops scanning for BLE advertisements. -template -void BLEV2::stopScanning() { - Synchronized s(lock_.get()); - - if (!isScanning()) { - // logger.atDebug().log("Can't turn off BLE scanning because we never - // started scanning."); - return; - } - - scanning_info_->on_lost_alarm->cancel(); - - ble_medium_->stopScanning(); - discovered_peripheral_tracker_->stopTracking(scanning_info_->service_id); - // Reset our bundle of scanning state to mark that we're no longer scanning. - scanning_info_.destroy(); -} - -// TODO(b/112199086) Change to RecurringCancelableAlarm -template -Ptr BLEV2::createOnLostAlarm() { - return Ptr(); -} - -// Returns true if the device is currently accepting incoming BLE socket -// connections. -template -bool BLEV2::isAcceptingConnections() { - Synchronized s(lock_.get()); - - return !accepting_connections_info_.isNull(); -} - -// Starts accepting incoming BLE socket connections. -template -bool BLEV2::startAcceptingConnections( - const string& service_id, - Ptr accepted_connection_callback) { - Synchronized s(lock_.get()); - - // Avoid leaks. - ScopedPtr> - scoped_accepted_connection_callback(accepted_connection_callback); - if (service_id.empty() || scoped_accepted_connection_callback.isNull()) { - // logger.atSevere().log("Refusing to start accepting BLE connections - // because at least one of serviceId or acceptedConnectionCallback is - // null."); - return false; - } - - if (isAcceptingConnections()) { - // logger.atSevere().log("Refusing to start accepting BLE connections for %s - // because another BLE server socket is already in-progress.", service_id); - return false; - } - - if (!bluetooth_radio_->isEnabled()) { - // logger.atSevere().log("Can't start accepting BLE connections for %s - // because Bluetooth isn't enabled.", service_id); - return false; - } - - if (!isAvailable()) { - // logger.atSevere().log("Can't start accepting BLE connections for %s - // because BLE is not available.", service_id); - return false; - } - - // TODO(ahlee): Implement w/ the rest of the connecting logic. - // Default to returning true and creating accepting_connections_info_ so we - // can test the advertising and discovery flow fully. - accepting_connections_info_ = - MakePtr(new AcceptingConnectionsInfo(service_id)); - return true; -} - -// Stops accepting incoming BLE socket connections. -template -void BLEV2::stopAcceptingConnections() { - Synchronized s(lock_.get()); - - if (!isAcceptingConnections()) { - // logger.atDebug().log("Can't stop accepting BLE connections because it was - // never started."); - return; - } - - ble_medium_->stopListeningForIncomingBLESockets(); - - // Reset our bundle of accepting connections state to mark that we're no - // longer accepting connections. - accepting_connections_info_.destroy(); -} - -// Note: getGattConnectionBackoffPeriodMillis is only used in the java version -// of reliablyConnect() for now. - -// Returns true if the advertisement GATT server is currently running. -template -bool BLEV2::isAdvertisementGattServerRunning() { - return !gatt_server_info_.isNull(); -} - -// Starts a GATT server to deliver additional advertisement data. Returns true -// if the server was started successfully. -template -bool BLEV2::startAdvertisementGattServer( - const string& service_id, ConstPtr advertisement) { - // advertisement is not being wrapped in a ScopedPtr because ownership is not - // passed on from startAdvertising(). - - if (isAdvertisementGattServerRunning()) { - // logger.atSevere().log("Refusing to start an advertisement GATT server - // because one is already running."); - return false; - } - - // Create a BleAdvertisement to wrap over the passed in advertisement. - ScopedPtr> legacy_service_id_hash( - generateServiceIdHash(BLEAdvertisement::Version::V1, service_id)); - ScopedPtr> legacy_ble_advertisement_bytes( - BLEAdvertisement::toBytes(BLEAdvertisement::Version::V1, - BLEAdvertisement::SocketVersion::V1, - legacy_service_id_hash.get(), advertisement)); - if (legacy_ble_advertisement_bytes.isNull()) { - // logger.atSevere().log("Refusing to start an advertisement GATT server - // because creating a legacy BleAdvertisement with service ID %s failed.", - // service_id); - return false; - } - - ScopedPtr> service_id_hash( - generateServiceIdHash(BLEAdvertisement::Version::V2, service_id)); - ScopedPtr> ble_advertisement_bytes( - BLEAdvertisement::toBytes(BLEAdvertisement::Version::V2, - BLEAdvertisement::SocketVersion::V2, - service_id_hash.get(), advertisement)); - if (ble_advertisement_bytes.isNull()) { - // logger.atSevere().log("Refusing to start an advertisement GATT server - // because creating a BleAdvertisement with service ID %s failed.", - // service_id); - return false; - } - - return internalStartAdvertisementGattServer( - legacy_ble_advertisement_bytes.release(), - ble_advertisement_bytes.release()); -} - -template -bool BLEV2::internalStartAdvertisementGattServer( - ConstPtr legacy_ble_advertisement_bytes, - ConstPtr ble_advertisement_bytes) { - // Avoid leaks. - ScopedPtr> scoped_legacy_ble_advertisement_bytes( - legacy_ble_advertisement_bytes); - ScopedPtr> scoped_ble_advertisement_bytes( - ble_advertisement_bytes); - - ScopedPtr> - connection_lifecycle_callback( - new ServerGATTConnectionLifecycleCallbackFacade(self_)); - ScopedPtr> gatt_server( - ble_medium_->startGATTServer(connection_lifecycle_callback.get())); - if (gatt_server.isNull()) { - // logger.atSevere().withCause(e).log("Unable to start an advertisement GATT - // server."); - return false; - } - - if (!generateAdvertisementCharacteristic( - /* slot= */ 0, scoped_legacy_ble_advertisement_bytes.release(), - gatt_server.get())) { - gatt_server->stop(); - return false; - } - - if (!generateAdvertisementCharacteristic( - /* slot= */ 1, scoped_ble_advertisement_bytes.release(), - gatt_server.get())) { - gatt_server->stop(); - return false; - } - - // GattCharacteristic is not included in GATTServerInfo because we don't need - // it after it's been updated. - gatt_server_info_ = MakePtr(new GATTServerInfo( - gatt_server.release(), connection_lifecycle_callback.release())); - return true; -} - -template -bool BLEV2::generateAdvertisementCharacteristic( - std::int32_t slot, ConstPtr advertisement, - Ptr gatt_server) { - // Avoid leaks. - ScopedPtr> scoped_advertisement(advertisement); - - std::set permissions; - permissions.insert(GATTCharacteristic::Permission::READ); - std::set properties; - properties.insert(GATTCharacteristic::Property::READ); - Ptr gatt_characteristic(gatt_server->createCharacteristic( - kCopresenceServiceUuid, generateAdvertisementUuid(slot), permissions, - properties)); - - if (gatt_characteristic.isNull()) { - // logger.atSevere().withCause(e).log("Unable to create and add a - // characterstic to the gatt server for the advertisement."); - return false; - } - - if (!gatt_server->updateCharacteristic(gatt_characteristic, - scoped_advertisement.release())) { - // logger.atSevere().withCause(e).log("Unable to write a value to the GATT - // characteristic."); - return false; - } - - return true; -} - -// Note: In the java counterpart this in a utils class. -// Generates a characteristic UUID for an advertisement at the given slot. -template -string BLEV2::generateAdvertisementUuid(std::int32_t slot) { - return UUID(kAdvertisementUuidMsb, kAdvertisementUuidLsb | slot) - .str(); -} - -// Stops a GATT server used for additional advertisement data. -template -void BLEV2::stopAdvertisementGattServer() { - Synchronized s(lock_.get()); - - if (!isAdvertisementGattServerRunning()) { - // logger.atSevere().log("Unable to stop the advertisement GATT server - // because it's not running."); - return; - } - - gatt_server_info_->gatt_server->stop(); - gatt_server_info_.destroy(); -} - -// Connects to a GATT server, reads advertisement data, and then disconnects -// from the GATT server. This method blocks until all advertisements are read, -// or a connection error occurs. -template -Ptr> -BLEV2::processFetchGattAdvertisementsRequest( - Ptr peripheral, std::int32_t num_slots, - Ptr> advertisement_read_result) { - Synchronized s(lock_.get()); - - if (advertisement_read_result.isNull()) { - advertisement_read_result = - MakeRefCountedPtr(new AdvertisementReadResult()); - } - - if (peripheral.isNull()) { - // logger.atSevere().log("Can't read from an advertisement GATT server - // because ble peripheral is null."); - return advertisement_read_result; - } - - if (!bluetooth_radio_->isEnabled()) { - // logger.atSevere().log("Can't read from an advertisement GATT server - // because Bluetooth was never turned on."); - return advertisement_read_result; - } - - if (!isAvailable()) { - // logger.atSevere().log("Can't read from an advertisement GATT server - // because BLE is not available."); - return advertisement_read_result; - } - - return internalReadFromAdvertisementGattServer(peripheral, num_slots, - advertisement_read_result); -} - -template -Ptr> -BLEV2::internalReadFromAdvertisementGattServer( - Ptr peripheral, std::int32_t num_slots, - Ptr> advertisement_read_result) { - // Attempt to connect and read some GATT characteristics. - bool read_success = true; - - ScopedPtr> - connection_lifecycle_callback( - new ClientGATTConnectionLifecycleCallbackFacade(self_)); - ScopedPtr> gatt_connection( - ble_medium_->connectToGATTServer(peripheral, kDefaultMtu, - BLEMediumV2::PowerMode::HIGH, - connection_lifecycle_callback.get())); - if (!gatt_connection.isNull() && gatt_connection->discoverServices()) { - // Read all advertisements from all slots that we haven't read from yet. - for (std::int32_t slot = 0; slot < num_slots; ++slot) { - // Make sure we haven't already read this advertisement before. - if (advertisement_read_result->hasAdvertisement(slot)) { - continue; - } - - // Make sure the characteristic even exists for this slot number. If the - // characteristic doesn't exist, we shouldn't count the fetch as a - // failure because there's nothing we could've done about a non-existent - // characteristic. - Ptr gatt_characteristic( - gatt_connection->getCharacteristic(kCopresenceServiceUuid, - generateAdvertisementUuid(slot))); - if (/* !advertisementSlotExists()= */ gatt_characteristic.isNull()) { - continue; - } - - // Read advertisement data from the characteristic associated with this - // slot. - ScopedPtr> characteristic_value( - gatt_connection->readCharacteristic(gatt_characteristic)); - if (!characteristic_value.isNull()) { - advertisement_read_result->addAdvertisement( - slot, characteristic_value.release()); - // logger.atVerbose().log("Successfully read advertisement at slot %d - // on peripheral %s.", slot, peripheral); - } else { - // logger.atWarning().withCause(characteristicReadException).log("Can't - // read advertisement for slot %d on peripheral %s.", slot, - // peripheral); - read_success = false; - } - // Whether or not we succeeded with this slot, we should try reading the - // other slots to get as many advertisements as possible before - // returning a success or failure. - } - - gatt_connection->disconnect(); - } else { - // logger.atWarning().withCause(connectException).log("Can't connect to an - // advertisement GATT server for peripheral %s.", peripheral); - read_success = false; - } - - advertisement_read_result->recordLastReadStatus(read_success); - return advertisement_read_result; -} - -template -void BLEV2::offloadFromPlatformThread(Ptr runnable) { - platform_thread_offloader_->execute(runnable); -} - -template -ConstPtr BLEV2::generateAdvertisementHash( - ConstPtr advertisement_bytes) { - return Utils::sha256Hash(hash_utils_.get(), advertisement_bytes, - BLEAdvertisementHeader::kAdvertisementHashLength); -} - -template -ConstPtr BLEV2::generateServiceIdHash( - BLEAdvertisement::Version::Value version, const string& service_id) { - ScopedPtr> service_id_bytes( - MakeConstPtr(new ByteArray(service_id.data(), service_id.size()))); - switch (version) { - case BLEAdvertisement::Version::V1: - return Utils::legacySha256HashOnlyForPrinting( - hash_utils_.get(), service_id_bytes.get(), - BLEAdvertisement::kServiceIdHashLength); - case BLEAdvertisement::Version::V2: - // Fall through. - case BLEAdvertisement::Version::UNKNOWN: - // Fall through. - default: - // Use the latest known hashing scheme. - return Utils::sha256Hash(hash_utils_.get(), service_id_bytes.get(), - BLEAdvertisement::kServiceIdHashLength); - } -} - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core/internal/mediums/ble_v2.h b/cpp/core/internal/mediums/ble_v2.h deleted file mode 100644 index 2e13802b..00000000 --- a/cpp/core/internal/mediums/ble_v2.h +++ /dev/null @@ -1,313 +0,0 @@ -#ifndef CORE_INTERNAL_MEDIUMS_BLE_V2_H_ -#define CORE_INTERNAL_MEDIUMS_BLE_V2_H_ - -#include - -#include "core/internal/mediums/advertisement_read_result.h" -#include "core/internal/mediums/ble_advertisement.h" -#include "core/internal/mediums/bluetooth_radio.h" -#include "core/internal/mediums/discovered_peripheral_callback.h" -#include "core/internal/mediums/discovered_peripheral_tracker.h" -#include "platform/api/ble_v2.h" -#include "platform/api/bluetooth_adapter.h" -#include "platform/api/hash_utils.h" -#include "platform/api/lock.h" -#include "platform/byte_array.h" -#include "platform/cancelable_alarm.h" -#include "platform/port/string.h" -#include "platform/prng.h" -#include "platform/ptr.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -namespace ble_v2 { - -template -class ProcessOnLostRunnable; - -template -class OnAdvertisementFoundRunnable; - -} // namespace ble_v2 - -template -class BLEV2 { - public: - explicit BLEV2(Ptr> bluetooth_radio); - ~BLEV2(); - - bool isAvailable(); - // While the start* functions for each action (advertising, scanning, - // accepting connections) take in a service_id, the stop* and is* functions do - // not. This is because the service_id isn't used. In the java code, shutdown - // calls all the stop* functions w/ a null service_id. The service_id is just - // passed through to the corresponding is* function, which ignores it. - // service_id should be added back in when C++ supports multi-client. - bool startAdvertising(const string& service_id, - ConstPtr advertisement, - BLEMediumV2::PowerMode::Value power_mode, - const string& fast_advertisement_service_uuid); - void stopAdvertising(); - - bool startScanning( - const string& service_id, - Ptr discovered_peripheral_callback, - BLEMediumV2::PowerMode::Value power_mode, - const string& fast_advertisement_service_uuid); - void stopScanning(); - - class AcceptedConnectionCallback { - public: - virtual ~AcceptedConnectionCallback() {} - - // TODO(ahlee): Add in connecting logic. - }; - - bool isAcceptingConnections(); - bool startAcceptingConnections( - const string& service_id, - Ptr accepted_connection_callback); - void stopAcceptingConnections(); - - private: - template - friend class ble_v2::ProcessOnLostRunnable; - template - friend class ble_v2::OnAdvertisementFoundRunnable; - - class GATTAdvertisementFetcherFacade - : public DiscoveredPeripheralTracker::GattAdvertisementFetcher { - public: - explicit GATTAdvertisementFetcherFacade(Ptr> impl) - : impl_(impl) {} - ~GATTAdvertisementFetcherFacade() override {} - - Ptr> fetchGattAdvertisements( - Ptr ble_peripheral, std::int32_t num_slots, - Ptr> advertisement_read_result) - override { - return impl_->processFetchGattAdvertisementsRequest( - ble_peripheral, num_slots, advertisement_read_result); - } - - private: - Ptr> impl_; - }; - - class ScanCallbackFacade : public BLEMediumV2::ScanCallback { - public: - explicit ScanCallbackFacade(Ptr> impl) : impl_(impl) {} - ~ScanCallbackFacade() override {} - - void onAdvertisementFound( - Ptr peripheral, - ConstPtr advertisement_data) override { - impl_->onAdvertisementFoundImpl(peripheral, advertisement_data); - } - - private: - Ptr> impl_; - }; - - class ClientGATTConnectionLifecycleCallbackFacade - : public ClientGATTConnectionLifecycleCallback { - public: - explicit ClientGATTConnectionLifecycleCallbackFacade( - Ptr> impl) - : impl_(impl) {} - ~ClientGATTConnectionLifecycleCallbackFacade() override {} - - void onDisconnected(Ptr connection) override { - // Avoid leaks. - ScopedPtr> scoped_connection(connection); - - // Nothing else to do for now. - } - - private: - Ptr> impl_; - }; - - class ServerGATTConnectionLifecycleCallbackFacade - : public ServerGATTConnectionLifecycleCallback { - public: - explicit ServerGATTConnectionLifecycleCallbackFacade( - Ptr> impl) - : impl_(impl) {} - ~ServerGATTConnectionLifecycleCallbackFacade() override {} - - void onCharacteristicSubscription( - Ptr connection, - Ptr characteristic) override { - // Avoid leaks. Do not scope the characteristic because it is ref counted - // by the per-platform ble_v2 implementation. - ScopedPtr> scoped_connection(connection); - - // Nothing else to do for now. - } - - void onCharacteristicUnsubscription( - Ptr connection, - Ptr characteristic) override { - // Avoid leaks. Do not scope the characteristic because it is ref counted - // by the per-platform ble_v2 implementation. - ScopedPtr> scoped_connection(connection); - - // Nothing else to do for now. - } - - private: - Ptr> impl_; - }; - - struct ScanningInfo { - ScanningInfo(const string& service_id, - Ptr scan_callback_facade, - Ptr on_lost_alarm) - : service_id(service_id), - scan_callback_facade(scan_callback_facade), - on_lost_alarm(on_lost_alarm) {} - ~ScanningInfo() { - // Nothing to do (the ScopedPtr members take care of themselves). - } - - const string service_id; - ScopedPtr> scan_callback_facade; - // TODO(ahlee): Change to recurring cancelable alarm - ScopedPtr> on_lost_alarm; - }; - - struct AdvertisingInfo { - explicit AdvertisingInfo(const string& service_id) - : service_id(service_id) {} - ~AdvertisingInfo() {} - - const string service_id; - }; - - struct GATTServerInfo { - GATTServerInfo(Ptr gatt_server, - Ptr - connection_lifecycle_callback) - : gatt_server(gatt_server), - connection_lifecycle_callback(connection_lifecycle_callback) {} - ~GATTServerInfo() { - // Nothing to do (the ScopedPtr members take care of themselves). - } - - ScopedPtr> gatt_server; - ScopedPtr> - connection_lifecycle_callback; - }; - - struct AcceptingConnectionsInfo { - explicit AcceptingConnectionsInfo(const string& service_id) - : service_id(service_id) {} - ~AcceptingConnectionsInfo() { - // Nothing to do (the ScopedPtr members take care of themselves). - } - - const string service_id; - // TODO(ahlee): Fill in. - }; - - static const std::int32_t kNumAdvertisementSlots; - static const std::int32_t kMaxAdvertisementLength; - static const std::int32_t kDummyServiceIdLength; - static const char* kCopresenceServiceUuid; - static const std::int64_t kOnLostTimeoutMillis; - static const std::int64_t kGattAdvertisementOperationTimeoutMillis; - static const std::int64_t kMinConnectionAttemptRecoveryDurationMillis; - static const std::int32_t kMaxConnectionAttemptRecoveryFuzzDurationMillis; - static const std::uint32_t kDefaultMtu; - static const std::int64_t kAdvertisementUuidMsb; - static const std::int64_t kAdvertisementUuidLsb; - - bool isAdvertising(); - ConstPtr createAdvertisementHeader( - const string& service_id, ConstPtr advertisement_bytes, - bool is_fast_advertisement); - - bool isScanning(); - void onAdvertisementFoundImpl( - Ptr ble_peripheral, - ConstPtr advertisement_data); - void processOnLostTimeout(); - Ptr createOnLostAlarm(); - - bool isAdvertisementGattServerRunning(); - bool startAdvertisementGattServer(const string& service_id, - ConstPtr advertisement); - bool internalStartAdvertisementGattServer( - ConstPtr legacy_ble_advertisement_bytes, - ConstPtr ble_advertisement_bytes); - bool generateAdvertisementCharacteristic( - std::int32_t slot, ConstPtr advertisement, - Ptr gatt_server); - void stopAdvertisementGattServer(); - - Ptr> processFetchGattAdvertisementsRequest( - Ptr peripheral, std::int32_t num_slots, - Ptr> advertisement_read_result); - Ptr> - internalReadFromAdvertisementGattServer( - Ptr ble_peripheral, std::int32_t num_slots, - Ptr> advertisement_read_result); - - void offloadFromPlatformThread(Ptr runnable); - // TODO(ahlee): Move these out to utils (also used by - // DiscoveredPeripheralTracker). - ConstPtr generateAdvertisementHash( - ConstPtr advertisement_bytes); - ConstPtr generateServiceIdHash( - BLEAdvertisement::Version::Value version, const string& service_id); - - // This maps to a helper function found in bluetoothlowenergy/Utils.java. In - // the C++ code we moved it because it's only used here. - string generateAdvertisementUuid(std::int32_t slot); - - // ------------ GENERAL ------------ - - ScopedPtr> lock_; - // Where we throw potentially blocking work off of the platform thread. - ScopedPtr> - platform_thread_offloader_; - ScopedPtr> prng_; - ScopedPtr> hash_utils_; - - // ------------ CORE BLE ------------ - - Ptr> bluetooth_radio_; - ScopedPtr> bluetooth_adapter_; - // The underlying, per-platform implementation. - ScopedPtr> ble_medium_; - - // ------------ DISCOVERY ------------ - - // scanning_info_ is not scoped because it's nullable. - Ptr scanning_info_; - ScopedPtr>> - discovered_peripheral_tracker_; - ScopedPtr> on_lost_executor_; - - // ------------ ADVERTISING ------------ - - // advertising_info_, gatt_server_info_, and accepting_connections_info_ are - // not scoped because they are nullable. - Ptr advertising_info_; - Ptr gatt_server_info_; - Ptr accepting_connections_info_; - std::shared_ptr self_{this, [](void*){}}; -}; - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location - -#include "core/internal/mediums/ble_v2.cc" - -#endif // CORE_INTERNAL_MEDIUMS_BLE_V2_H_ diff --git a/cpp/core_v2/internal/mediums/ble_v2/BUILD b/cpp/core/internal/mediums/ble_v2/BUILD similarity index 75% rename from cpp/core_v2/internal/mediums/ble_v2/BUILD rename to cpp/core/internal/mediums/ble_v2/BUILD index 85ba9fd9..d3596825 100644 --- a/cpp/core_v2/internal/mediums/ble_v2/BUILD +++ b/cpp/core/internal/mediums/ble_v2/BUILD @@ -15,14 +15,14 @@ cc_library( "discovered_peripheral_callback.h", ], visibility = [ - "//core_v2/internal:__subpackages__", + "//core/internal:__subpackages__", ], deps = [ - "//core_v2:core_types", - "//platform_v2/base", - "//platform_v2/base:util", - "//platform_v2/public:logging", - "//platform_v2/public:types", + "//core:core_types", + "//platform/base", + "//platform/base:util", + "//platform/public:logging", + "//platform/public:types", "//absl/container:flat_hash_map", "//absl/container:flat_hash_set", "//absl/strings", @@ -41,8 +41,8 @@ cc_test( ], deps = [ ":ble_v2", - "//platform_v2/base", - "//platform_v2/impl/g3", # buildcleaner: keep + "//platform/base", + "//platform/impl/g3", # buildcleaner: keep "//testing/base/public:gunit_main", "//absl/time", ], diff --git a/cpp/core_v2/internal/mediums/ble_v2/advertisement_read_result.cc b/cpp/core/internal/mediums/ble_v2/advertisement_read_result.cc similarity index 97% rename from cpp/core_v2/internal/mediums/ble_v2/advertisement_read_result.cc rename to cpp/core/internal/mediums/ble_v2/advertisement_read_result.cc index 63e43127..28b593cd 100644 --- a/cpp/core_v2/internal/mediums/ble_v2/advertisement_read_result.cc +++ b/cpp/core/internal/mediums/ble_v2/advertisement_read_result.cc @@ -1,9 +1,9 @@ -#include "core_v2/internal/mediums/ble_v2/advertisement_read_result.h" +#include "core/internal/mediums/ble_v2/advertisement_read_result.h" #include #include -#include "platform_v2/public/mutex_lock.h" +#include "platform/public/mutex_lock.h" #include "absl/container/flat_hash_set.h" #include "absl/time/clock.h" diff --git a/cpp/core_v2/internal/mediums/ble_v2/advertisement_read_result.h b/cpp/core/internal/mediums/ble_v2/advertisement_read_result.h similarity index 89% rename from cpp/core_v2/internal/mediums/ble_v2/advertisement_read_result.h rename to cpp/core/internal/mediums/ble_v2/advertisement_read_result.h index ebf5b535..a9ae74d1 100644 --- a/cpp/core_v2/internal/mediums/ble_v2/advertisement_read_result.h +++ b/cpp/core/internal/mediums/ble_v2/advertisement_read_result.h @@ -1,12 +1,12 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_BLE_V2_ADVERTISEMENT_READ_RESULT_H_ -#define CORE_V2_INTERNAL_MEDIUMS_BLE_V2_ADVERTISEMENT_READ_RESULT_H_ +#ifndef CORE_INTERNAL_MEDIUMS_BLE_V2_ADVERTISEMENT_READ_RESULT_H_ +#define CORE_INTERNAL_MEDIUMS_BLE_V2_ADVERTISEMENT_READ_RESULT_H_ #include #include -#include "platform_v2/base/byte_array.h" -#include "platform_v2/public/mutex.h" -#include "platform_v2/public/system_clock.h" +#include "platform/base/byte_array.h" +#include "platform/public/mutex.h" +#include "platform/public/system_clock.h" #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "absl/time/clock.h" @@ -87,4 +87,4 @@ class AdvertisementReadResult { } // namespace nearby } // namespace location -#endif // CORE_V2_INTERNAL_MEDIUMS_BLE_V2_ADVERTISEMENT_READ_RESULT_H_ +#endif // CORE_INTERNAL_MEDIUMS_BLE_V2_ADVERTISEMENT_READ_RESULT_H_ diff --git a/cpp/core_v2/internal/mediums/ble_v2/advertisement_read_result_test.cc b/cpp/core/internal/mediums/ble_v2/advertisement_read_result_test.cc similarity index 98% rename from cpp/core_v2/internal/mediums/ble_v2/advertisement_read_result_test.cc rename to cpp/core/internal/mediums/ble_v2/advertisement_read_result_test.cc index 7acfef4e..bdf41a70 100644 --- a/cpp/core_v2/internal/mediums/ble_v2/advertisement_read_result_test.cc +++ b/cpp/core/internal/mediums/ble_v2/advertisement_read_result_test.cc @@ -1,4 +1,4 @@ -#include "core_v2/internal/mediums/ble_v2/advertisement_read_result.h" +#include "core/internal/mediums/ble_v2/advertisement_read_result.h" #include "gtest/gtest.h" #include "absl/time/clock.h" diff --git a/cpp/core_v2/internal/mediums/ble_v2/ble_advertisement.cc b/cpp/core/internal/mediums/ble_v2/ble_advertisement.cc similarity index 98% rename from cpp/core_v2/internal/mediums/ble_v2/ble_advertisement.cc rename to cpp/core/internal/mediums/ble_v2/ble_advertisement.cc index 2011d925..de8e382b 100644 --- a/cpp/core_v2/internal/mediums/ble_v2/ble_advertisement.cc +++ b/cpp/core/internal/mediums/ble_v2/ble_advertisement.cc @@ -1,9 +1,9 @@ -#include "core_v2/internal/mediums/ble_v2/ble_advertisement.h" +#include "core/internal/mediums/ble_v2/ble_advertisement.h" #include -#include "platform_v2/base/base_input_stream.h" -#include "platform_v2/public/logging.h" +#include "platform/base/base_input_stream.h" +#include "platform/public/logging.h" #include "absl/strings/str_cat.h" namespace location { diff --git a/cpp/core_v2/internal/mediums/ble_v2/ble_advertisement.h b/cpp/core/internal/mediums/ble_v2/ble_advertisement.h similarity index 95% rename from cpp/core_v2/internal/mediums/ble_v2/ble_advertisement.h rename to cpp/core/internal/mediums/ble_v2/ble_advertisement.h index 3b8ad37d..8bef3916 100644 --- a/cpp/core_v2/internal/mediums/ble_v2/ble_advertisement.h +++ b/cpp/core/internal/mediums/ble_v2/ble_advertisement.h @@ -1,9 +1,9 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_H_ -#define CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_H_ +#ifndef CORE_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_H_ +#define CORE_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_H_ #include -#include "platform_v2/base/byte_array.h" +#include "platform/base/byte_array.h" namespace location { namespace nearby { @@ -122,4 +122,4 @@ class BleAdvertisement { } // namespace nearby } // namespace location -#endif // CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_H_ +#endif // CORE_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_H_ diff --git a/cpp/core_v2/internal/mediums/ble_v2/ble_advertisement_header.cc b/cpp/core/internal/mediums/ble_v2/ble_advertisement_header.cc similarity index 94% rename from cpp/core_v2/internal/mediums/ble_v2/ble_advertisement_header.cc rename to cpp/core/internal/mediums/ble_v2/ble_advertisement_header.cc index 5c35fafa..293e3d9b 100644 --- a/cpp/core_v2/internal/mediums/ble_v2/ble_advertisement_header.cc +++ b/cpp/core/internal/mediums/ble_v2/ble_advertisement_header.cc @@ -1,10 +1,10 @@ -#include "core_v2/internal/mediums/ble_v2/ble_advertisement_header.h" +#include "core/internal/mediums/ble_v2/ble_advertisement_header.h" #include -#include "platform_v2/base/base64_utils.h" -#include "platform_v2/base/base_input_stream.h" -#include "platform_v2/public/logging.h" +#include "platform/base/base64_utils.h" +#include "platform/base/base_input_stream.h" +#include "platform/public/logging.h" #include "absl/strings/str_cat.h" namespace location { diff --git a/cpp/core_v2/internal/mediums/ble_v2/ble_advertisement_header.h b/cpp/core/internal/mediums/ble_v2/ble_advertisement_header.h similarity index 92% rename from cpp/core_v2/internal/mediums/ble_v2/ble_advertisement_header.h rename to cpp/core/internal/mediums/ble_v2/ble_advertisement_header.h index b4c1289e..2c214b4e 100644 --- a/cpp/core_v2/internal/mediums/ble_v2/ble_advertisement_header.h +++ b/cpp/core/internal/mediums/ble_v2/ble_advertisement_header.h @@ -1,9 +1,9 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_HEADER_H_ -#define CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_HEADER_H_ +#ifndef CORE_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_HEADER_H_ +#define CORE_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_HEADER_H_ #include -#include "platform_v2/base/byte_array.h" +#include "platform/base/byte_array.h" namespace location { namespace nearby { @@ -80,4 +80,4 @@ class BleAdvertisementHeader { } // namespace nearby } // namespace location -#endif // CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_HEADER_H_ +#endif // CORE_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_HEADER_H_ diff --git a/cpp/core_v2/internal/mediums/ble_v2/ble_advertisement_header_test.cc b/cpp/core/internal/mediums/ble_v2/ble_advertisement_header_test.cc similarity index 98% rename from cpp/core_v2/internal/mediums/ble_v2/ble_advertisement_header_test.cc rename to cpp/core/internal/mediums/ble_v2/ble_advertisement_header_test.cc index 10aa62d0..c24a2b03 100644 --- a/cpp/core_v2/internal/mediums/ble_v2/ble_advertisement_header_test.cc +++ b/cpp/core/internal/mediums/ble_v2/ble_advertisement_header_test.cc @@ -1,6 +1,6 @@ -#include "core_v2/internal/mediums/ble_v2/ble_advertisement_header.h" +#include "core/internal/mediums/ble_v2/ble_advertisement_header.h" -#include "platform_v2/base/base64_utils.h" +#include "platform/base/base64_utils.h" #include "gtest/gtest.h" namespace location { diff --git a/cpp/core_v2/internal/mediums/ble_v2/ble_advertisement_test.cc b/cpp/core/internal/mediums/ble_v2/ble_advertisement_test.cc similarity index 99% rename from cpp/core_v2/internal/mediums/ble_v2/ble_advertisement_test.cc rename to cpp/core/internal/mediums/ble_v2/ble_advertisement_test.cc index 6bbbd196..0c5a62b8 100644 --- a/cpp/core_v2/internal/mediums/ble_v2/ble_advertisement_test.cc +++ b/cpp/core/internal/mediums/ble_v2/ble_advertisement_test.cc @@ -1,4 +1,4 @@ -#include "core_v2/internal/mediums/ble_v2/ble_advertisement.h" +#include "core/internal/mediums/ble_v2/ble_advertisement.h" #include diff --git a/cpp/core_v2/internal/mediums/ble_v2/ble_packet.cc b/cpp/core/internal/mediums/ble_v2/ble_packet.cc similarity index 91% rename from cpp/core_v2/internal/mediums/ble_v2/ble_packet.cc rename to cpp/core/internal/mediums/ble_v2/ble_packet.cc index c98d7c38..d58fb7db 100644 --- a/cpp/core_v2/internal/mediums/ble_v2/ble_packet.cc +++ b/cpp/core/internal/mediums/ble_v2/ble_packet.cc @@ -1,7 +1,7 @@ -#include "core_v2/internal/mediums/ble_v2/ble_packet.h" +#include "core/internal/mediums/ble_v2/ble_packet.h" -#include "platform_v2/base/base_input_stream.h" -#include "platform_v2/public/logging.h" +#include "platform/base/base_input_stream.h" +#include "platform/public/logging.h" #include "absl/strings/str_cat.h" namespace location { diff --git a/cpp/core_v2/internal/mediums/ble_v2/ble_packet.h b/cpp/core/internal/mediums/ble_v2/ble_packet.h similarity index 85% rename from cpp/core_v2/internal/mediums/ble_v2/ble_packet.h rename to cpp/core/internal/mediums/ble_v2/ble_packet.h index 1e7172ae..c5af2cbd 100644 --- a/cpp/core_v2/internal/mediums/ble_v2/ble_packet.h +++ b/cpp/core/internal/mediums/ble_v2/ble_packet.h @@ -1,9 +1,9 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_PACKET_H_ -#define CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_PACKET_H_ +#ifndef CORE_INTERNAL_MEDIUMS_BLE_V2_BLE_PACKET_H_ +#define CORE_INTERNAL_MEDIUMS_BLE_V2_BLE_PACKET_H_ #include -#include "platform_v2/base/byte_array.h" +#include "platform/base/byte_array.h" namespace location { namespace nearby { @@ -47,4 +47,4 @@ class BlePacket { } // namespace nearby } // namespace location -#endif // CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_PACKET_H_ +#endif // CORE_INTERNAL_MEDIUMS_BLE_V2_BLE_PACKET_H_ diff --git a/cpp/core_v2/internal/mediums/ble_v2/ble_packet_test.cc b/cpp/core/internal/mediums/ble_v2/ble_packet_test.cc similarity index 97% rename from cpp/core_v2/internal/mediums/ble_v2/ble_packet_test.cc rename to cpp/core/internal/mediums/ble_v2/ble_packet_test.cc index 9b0f6a99..11984546 100644 --- a/cpp/core_v2/internal/mediums/ble_v2/ble_packet_test.cc +++ b/cpp/core/internal/mediums/ble_v2/ble_packet_test.cc @@ -1,4 +1,4 @@ -#include "core_v2/internal/mediums/ble_v2/ble_packet.h" +#include "core/internal/mediums/ble_v2/ble_packet.h" #include "gtest/gtest.h" diff --git a/cpp/core_v2/internal/mediums/ble_v2/ble_peripheral.h b/cpp/core/internal/mediums/ble_v2/ble_peripheral.h similarity index 78% rename from cpp/core_v2/internal/mediums/ble_v2/ble_peripheral.h rename to cpp/core/internal/mediums/ble_v2/ble_peripheral.h index e144489f..bc61c59f 100644 --- a/cpp/core_v2/internal/mediums/ble_v2/ble_peripheral.h +++ b/cpp/core/internal/mediums/ble_v2/ble_peripheral.h @@ -1,7 +1,7 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_PERIPHERAL_H_ -#define CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_PERIPHERAL_H_ +#ifndef CORE_INTERNAL_MEDIUMS_BLE_V2_BLE_PERIPHERAL_H_ +#define CORE_INTERNAL_MEDIUMS_BLE_V2_BLE_PERIPHERAL_H_ -#include "platform_v2/base/byte_array.h" +#include "platform/base/byte_array.h" namespace location { namespace nearby { @@ -32,4 +32,4 @@ class BlePeripheral { } // namespace nearby } // namespace location -#endif // CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_PERIPHERAL_H_ +#endif // CORE_INTERNAL_MEDIUMS_BLE_V2_BLE_PERIPHERAL_H_ diff --git a/cpp/core_v2/internal/mediums/ble_v2/ble_peripheral_test.cc b/cpp/core/internal/mediums/ble_v2/ble_peripheral_test.cc similarity index 91% rename from cpp/core_v2/internal/mediums/ble_v2/ble_peripheral_test.cc rename to cpp/core/internal/mediums/ble_v2/ble_peripheral_test.cc index 59a06260..f5a41c00 100644 --- a/cpp/core_v2/internal/mediums/ble_v2/ble_peripheral_test.cc +++ b/cpp/core/internal/mediums/ble_v2/ble_peripheral_test.cc @@ -1,4 +1,4 @@ -#include "core_v2/internal/mediums/ble_v2/ble_peripheral.h" +#include "core/internal/mediums/ble_v2/ble_peripheral.h" #include "gtest/gtest.h" diff --git a/cpp/core_v2/internal/mediums/ble_v2/discovered_peripheral_callback.h b/cpp/core/internal/mediums/ble_v2/discovered_peripheral_callback.h similarity index 70% rename from cpp/core_v2/internal/mediums/ble_v2/discovered_peripheral_callback.h rename to cpp/core/internal/mediums/ble_v2/discovered_peripheral_callback.h index 92b63adf..c23ed828 100644 --- a/cpp/core_v2/internal/mediums/ble_v2/discovered_peripheral_callback.h +++ b/cpp/core/internal/mediums/ble_v2/discovered_peripheral_callback.h @@ -1,9 +1,9 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_BLE_V2_DISCOVERED_PERIPHERAL_CALLBACK_H_ -#define CORE_V2_INTERNAL_MEDIUMS_BLE_V2_DISCOVERED_PERIPHERAL_CALLBACK_H_ +#ifndef CORE_INTERNAL_MEDIUMS_BLE_V2_DISCOVERED_PERIPHERAL_CALLBACK_H_ +#define CORE_INTERNAL_MEDIUMS_BLE_V2_DISCOVERED_PERIPHERAL_CALLBACK_H_ -#include "core_v2/internal/mediums/ble_v2/ble_peripheral.h" -#include "core_v2/listeners.h" -#include "platform_v2/base/byte_array.h" +#include "core/internal/mediums/ble_v2/ble_peripheral.h" +#include "core/listeners.h" +#include "platform/base/byte_array.h" namespace location { namespace nearby { @@ -28,4 +28,4 @@ struct DiscoveredPeripheralCallback { } // namespace nearby } // namespace location -#endif // CORE_V2_INTERNAL_MEDIUMS_BLE_V2_DISCOVERED_PERIPHERAL_CALLBACK_H_ +#endif // CORE_INTERNAL_MEDIUMS_BLE_V2_DISCOVERED_PERIPHERAL_CALLBACK_H_ diff --git a/cpp/core/internal/mediums/bloom_filter.cc b/cpp/core/internal/mediums/bloom_filter.cc index 835ed205..2df09bef 100644 --- a/cpp/core/internal/mediums/bloom_filter.cc +++ b/cpp/core/internal/mediums/bloom_filter.cc @@ -9,31 +9,19 @@ namespace nearby { namespace connections { namespace mediums { -template -const std::int32_t BloomFilter::kHasherNumberOfRepetitions = 5; - -template -BloomFilter::BloomFilter() : bits_() {} - -template -BloomFilter::BloomFilter(ConstPtr bytes) : bits_() { - const char* bytes_read_ptr = bytes->getData(); - for (size_t byte_index = 0; byte_index < bytes->size(); byte_index++) { +BloomFilterBase::BloomFilterBase(const ByteArray& bytes, BitSet* bit_set) + : bits_(bit_set) { + const char* bytes_read_ptr = bytes.data(); + for (size_t byte_index = 0; byte_index < bytes.size(); byte_index++) { for (size_t bit_index = 0; bit_index < 8; bit_index++) { - bits_.set((byte_index * 8) + bit_index, - (*bytes_read_ptr >> bit_index) & 0x01); + bits_->Set((byte_index * 8) + bit_index, + (*bytes_read_ptr >> bit_index) & 0x01); } bytes_read_ptr++; } } -template -BloomFilter::~BloomFilter() { - // Nothing to do. -} - -template -ConstPtr BloomFilter::asBytes() { +BloomFilterBase::operator ByteArray() const { // Gets a binary string representation of the bitset where the leftmost // character corresponds to bitset position (total size) - 1. // @@ -41,13 +29,13 @@ ConstPtr BloomFilter::asBytes() { // [position 0] 0 0 1 1 0 0 0 1 0 1 0 1 [position 11] // The string representation will be outputted like this: // "1 0 1 0 1 0 0 0 1 1 0 0" - std::string bitset_binary_string = bits_.to_string(); + std::string bitset_binary_string = bits_->ToString(); - Ptr result_bytes{new ByteArray{CapacityInBytes}}; - char* result_bytes_write_ptr = result_bytes->getData(); + ByteArray result_bytes(GetMinBytesForBits()); + char* result_bytes_write_ptr = result_bytes.data(); // We go through the string backwards because the rightmost character // corresponds to position 0 in the bitset. - for (size_t i = bits_.size(); i > 0; i -= 8) { + for (size_t i = bits_->Size(); i > 0; i -= 8) { std::string byte_binary_string = bitset_binary_string.substr(i - 8, 8); std::uint32_t byte_value; absl::numbers_internal::safe_strtou32_base(byte_binary_string, &byte_value, @@ -55,35 +43,29 @@ ConstPtr BloomFilter::asBytes() { *result_bytes_write_ptr = static_cast(byte_value & 0x000000FF); result_bytes_write_ptr++; } - return ConstifyPtr(result_bytes); + return result_bytes; } -template -void BloomFilter::add(const std::string& s) { - std::vector hashes = getHashes(s); - for (std::vector::iterator it = hashes.begin(); - it != hashes.end(); ++it) { - size_t position = static_cast(*it) % bits_.size(); - bits_.set(position); +void BloomFilterBase::Add(const std::string& s) { + std::vector hashes = GetHashes(s); + for (int32_t hash : hashes) { + size_t position = static_cast(hash) % bits_->Size(); + bits_->Set(position, true); } } -template -bool BloomFilter::possiblyContains(const std::string& s) { - std::vector hashes = getHashes(s); - for (std::vector::iterator i = hashes.begin(); - i != hashes.end(); ++i) { - size_t position = static_cast(*i) % bits_.size(); - if (!bits_.test(position)) { +bool BloomFilterBase::PossiblyContains(const std::string& s) { + std::vector hashes = GetHashes(s); + for (int32_t hash : hashes) { + size_t position = static_cast(hash) % bits_->Size(); + if (!bits_->Test(position)) { return false; } } return true; } -template -std::vector BloomFilter::getHashes( - const std::string& s) { +std::vector BloomFilterBase::GetHashes(const std::string& s) { std::vector hashes(kHasherNumberOfRepetitions, 0); absl::uint128 hash128; diff --git a/cpp/core/internal/mediums/bloom_filter.h b/cpp/core/internal/mediums/bloom_filter.h index d358cb25..7150d864 100644 --- a/cpp/core/internal/mediums/bloom_filter.h +++ b/cpp/core/internal/mediums/bloom_filter.h @@ -2,12 +2,9 @@ #define CORE_INTERNAL_MEDIUMS_BLOOM_FILTER_H_ #include -#include #include -#include "platform/byte_array.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "platform/base/byte_array.h" namespace location { namespace nearby { @@ -23,25 +20,63 @@ namespace mediums { * the bit set to ensure the bit set's length is a multiple of 8 (and can * neatly be returned as a ByteArray). */ -template -class BloomFilter { +class BloomFilterBase { public: - BloomFilter(); - explicit BloomFilter(ConstPtr bytes); - ~BloomFilter(); + explicit operator ByteArray() const; - ConstPtr asBytes(); + void Add(const std::string& s); + bool PossiblyContains(const std::string& s); - void add(const std::string& s); + protected: + class BitSet { + public: + virtual ~BitSet() = default; + virtual std::string ToString() const = 0; + virtual void Set(size_t pos, bool value) = 0; + virtual bool Test(size_t pos) const = 0; + virtual size_t Size() const = 0; + }; - bool possiblyContains(const std::string& s); + BloomFilterBase(const ByteArray& bytes, BitSet* bit_set); + virtual ~BloomFilterBase() = default; + + constexpr static int kHasherNumberOfRepetitions = 5; + std::vector GetHashes(const std::string& s); private: - static const std::int32_t kHasherNumberOfRepetitions; + int GetMinBytesForBits() const { return (bits_->Size() + 7) >> 3; } - std::vector getHashes(const std::string& s); + BitSet* bits_; +}; - std::bitset bits_; +template +class BloomFilter final : public BloomFilterBase { + public: + BloomFilter() : BloomFilterBase(ByteArray{}, &bits_) {} + explicit BloomFilter(const ByteArray& bytes) + : BloomFilterBase(bytes, &bits_) {} + BloomFilter(const BloomFilter&) = default; + BloomFilter& operator=(const BloomFilter&) = default; + BloomFilter(BloomFilter&& other) : BloomFilterBase(ByteArray{}, &bits_) { + *this = std::move(other); + } + BloomFilter& operator=(BloomFilter&& other) { + std::swap((*this).bits_, other.bits_); + return *this; + } + ~BloomFilter() override = default; + + private: + class BitSetImpl final : public BitSet { + public: + std::string ToString() const override { return bits_.to_string(); } + void Set(size_t pos, bool value) override { bits_.set(pos, value); } + bool Test(size_t pos) const override { return bits_.test(pos); } + size_t Size() const override { return bits_.size(); } + + private: + std::bitset bits_; + } bits_; }; } // namespace mediums @@ -49,6 +84,4 @@ class BloomFilter { } // namespace nearby } // namespace location -#include "core/internal/mediums/bloom_filter.cc" - #endif // CORE_INTERNAL_MEDIUMS_BLOOM_FILTER_H_ diff --git a/cpp/core/internal/mediums/bloom_filter_test.cc b/cpp/core/internal/mediums/bloom_filter_test.cc index 00ad384a..96d80c15 100644 --- a/cpp/core/internal/mediums/bloom_filter_test.cc +++ b/cpp/core/internal/mediums/bloom_filter_test.cc @@ -10,68 +10,102 @@ namespace connections { namespace mediums { namespace { -const size_t kByteArrayLength = 100; +constexpr size_t kByteArrayLength = 100; TEST(BloomFilterTest, EmptyFilterReturnsEmptyArray) { - ScopedPtr>> scoped_bloom_filter( - new BloomFilter()); + BloomFilter bloom_filter; - ScopedPtr> scoped_bloom_filter_bytes( - scoped_bloom_filter->asBytes()); + ByteArray bloom_filter_bytes(bloom_filter); std::string empty_string(kByteArrayLength, '\0'); - ASSERT_EQ(0, memcmp(scoped_bloom_filter_bytes->getData(), empty_string.data(), - empty_string.size())); + + EXPECT_EQ(empty_string, std::string(bloom_filter_bytes)); } TEST(BloomFilterTest, EmptyFilterNeverContains) { - ScopedPtr>> scoped_bloom_filter( - new BloomFilter()); + BloomFilter bloom_filter; - ASSERT_FALSE(scoped_bloom_filter->possiblyContains("ELEMENT_1")); - ASSERT_FALSE(scoped_bloom_filter->possiblyContains("ELEMENT_2")); - ASSERT_FALSE(scoped_bloom_filter->possiblyContains("ELEMENT_3")); + EXPECT_FALSE(bloom_filter.PossiblyContains("ELEMENT_1")); + EXPECT_FALSE(bloom_filter.PossiblyContains("ELEMENT_2")); + EXPECT_FALSE(bloom_filter.PossiblyContains("ELEMENT_3")); } TEST(BloomFilterTest, AddSuccess) { - ScopedPtr>> scoped_bloom_filter( - new BloomFilter()); - ASSERT_FALSE(scoped_bloom_filter->possiblyContains("ELEMENT_1")); + BloomFilter bloom_filter; - scoped_bloom_filter->add("ELEMENT_1"); - ASSERT_TRUE(scoped_bloom_filter->possiblyContains("ELEMENT_1")); + EXPECT_FALSE(bloom_filter.PossiblyContains("ELEMENT_1")); + + bloom_filter.Add("ELEMENT_1"); + + EXPECT_TRUE(bloom_filter.PossiblyContains("ELEMENT_1")); } TEST(BloomFilterTest, AddOnlyGivenArg) { - ScopedPtr>> scoped_bloom_filter( - new BloomFilter()); - scoped_bloom_filter->add("ELEMENT_1"); + BloomFilter bloom_filter; - ASSERT_TRUE(scoped_bloom_filter->possiblyContains("ELEMENT_1")); - ASSERT_FALSE(scoped_bloom_filter->possiblyContains("ELEMENT_2")); - ASSERT_FALSE(scoped_bloom_filter->possiblyContains("ELEMENT_3")); + bloom_filter.Add("ELEMENT_1"); + + EXPECT_TRUE(bloom_filter.PossiblyContains("ELEMENT_1")); + EXPECT_FALSE(bloom_filter.PossiblyContains("ELEMENT_2")); + EXPECT_FALSE(bloom_filter.PossiblyContains("ELEMENT_3")); } TEST(BloomFilterTest, AddMultipleArgs) { - ScopedPtr>> scoped_bloom_filter( - new BloomFilter()); - scoped_bloom_filter->add("ELEMENT_1"); - scoped_bloom_filter->add("ELEMENT_2"); + BloomFilter bloom_filter; - ASSERT_TRUE(scoped_bloom_filter->possiblyContains("ELEMENT_1")); - ASSERT_TRUE(scoped_bloom_filter->possiblyContains("ELEMENT_2")); - ASSERT_FALSE(scoped_bloom_filter->possiblyContains("ELEMENT_3")); + bloom_filter.Add("ELEMENT_1"); + bloom_filter.Add("ELEMENT_2"); + + EXPECT_TRUE(bloom_filter.PossiblyContains("ELEMENT_1")); + EXPECT_TRUE(bloom_filter.PossiblyContains("ELEMENT_2")); + EXPECT_FALSE(bloom_filter.PossiblyContains("ELEMENT_3")); } TEST(BloomFilterTest, AddMultipleArgsReturnsNonemptyArray) { - ScopedPtr>> scoped_bloom_filter(new BloomFilter<10>()); - scoped_bloom_filter->add("ELEMENT_1"); - scoped_bloom_filter->add("ELEMENT_2"); - scoped_bloom_filter->add("ELEMENT_3"); + BloomFilter<10> bloom_filter; - ScopedPtr> scoped_bloom_filter_bytes( - scoped_bloom_filter->asBytes()); + bloom_filter.Add("ELEMENT_1"); + bloom_filter.Add("ELEMENT_2"); + bloom_filter.Add("ELEMENT_3"); + + ByteArray bloom_filter_bytes(bloom_filter); std::string empty_string(kByteArrayLength, '\0'); - ASSERT_NE(scoped_bloom_filter_bytes->asString(), empty_string); + + EXPECT_NE(std::string(bloom_filter_bytes), empty_string); +} + +TEST(BloomFilterTest, CopyConstructorAndAssignmentSuccess) { + BloomFilter bloom_filter; + + EXPECT_FALSE(bloom_filter.PossiblyContains("ELEMENT_1")); + + bloom_filter.Add("ELEMENT_1"); + + BloomFilter bloom_filter_copy_1{bloom_filter}; + BloomFilter bloom_filter_copy_2 = bloom_filter; + + EXPECT_TRUE(bloom_filter.PossiblyContains("ELEMENT_1")); + EXPECT_TRUE(bloom_filter_copy_1.PossiblyContains("ELEMENT_1")); + EXPECT_TRUE(bloom_filter_copy_2.PossiblyContains("ELEMENT_1")); +} + +TEST(BloomFilterTest, MoveConstructorSuccess) { + BloomFilter bloom_filter; + + bloom_filter.Add("ELEMENT_1"); + + BloomFilter bloom_filter_move{std::move(bloom_filter)}; + + EXPECT_TRUE(bloom_filter_move.PossiblyContains("ELEMENT_1")); +} + +TEST(BloomFilterTest, MoveAssignmentSuccess) { + BloomFilter bloom_filter; + + bloom_filter.Add("ELEMENT_1"); + + BloomFilter bloom_filter_move = std::move(bloom_filter); + + EXPECT_TRUE(bloom_filter_move.PossiblyContains("ELEMENT_1")); } /** @@ -86,10 +120,10 @@ TEST(BloomFilterTest, AddMultipleArgsReturnsNonemptyArray) { * something like [ 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, ..., 1, 0]. */ TEST(BloomFilterTest, RandomnessNoEndBias) { - ScopedPtr>> scoped_bloom_filter( - new BloomFilter()); + BloomFilter bloom_filter; + // Add one element to our BloomFilter. - scoped_bloom_filter->add("ELEMENT_1"); + bloom_filter.Add("ELEMENT_1"); std::int32_t non_zero_count = 0; std::int32_t longest_zero_streak = 0; @@ -98,11 +132,9 @@ TEST(BloomFilterTest, RandomnessNoEndBias) { // Record the amount of non-zero bytes and the longest streak of zero bytes in // the resulting BloomFilter. This is an approximation of reasonable // distribution since we're recording by bytes instead of bits. - ScopedPtr> scoped_bloom_filter_bytes( - scoped_bloom_filter->asBytes()); - const char* bloom_filter_bytes_read_ptr = - scoped_bloom_filter_bytes->getData(); - for (int i = 0; i < scoped_bloom_filter_bytes->size(); i++) { + ByteArray bloom_filter_bytes(bloom_filter); + const char* bloom_filter_bytes_read_ptr = bloom_filter_bytes.data(); + for (int i = 0; i < bloom_filter_bytes.size(); i++) { if (*bloom_filter_bytes_read_ptr == '\0') { current_zero_streak++; } else { @@ -127,31 +159,31 @@ TEST(BloomFilterTest, RandomnessNoEndBias) { // kByteArrayLength - one end of the array. std::int32_t longest_acceptable_zero_streak = kByteArrayLength - (kByteArrayLength / non_zero_count); - ASSERT_TRUE(longest_zero_streak <= longest_acceptable_zero_streak); + + EXPECT_TRUE(longest_zero_streak <= longest_acceptable_zero_streak); } TEST(BloomFilterTest, RandomnessFalsePositiveRate) { - ScopedPtr>> scoped_bloom_filter(new BloomFilter<10>()); + BloomFilter<10> bloom_filter; + // Add 5 distinct elements to the BloomFilter. - scoped_bloom_filter->add("ELEMENT_1"); - scoped_bloom_filter->add("ELEMENT_2"); - scoped_bloom_filter->add("ELEMENT_3"); - scoped_bloom_filter->add("ELEMENT_4"); - scoped_bloom_filter->add("ELEMENT_5"); + bloom_filter.Add("ELEMENT_1"); + bloom_filter.Add("ELEMENT_2"); + bloom_filter.Add("ELEMENT_3"); + bloom_filter.Add("ELEMENT_4"); + bloom_filter.Add("ELEMENT_5"); std::int32_t false_positives = 0; // Now test 100 other elements and record the number of false positives. for (int i = 5; i < 105; i++) { false_positives += - scoped_bloom_filter->possiblyContains("ELEMENT_" + std::to_string(i)) - ? 1 - : 0; + bloom_filter.PossiblyContains("ELEMENT_" + std::to_string(i)) ? 1 : 0; } // We expect the false positive rate to be 3% with 5 elements in a 10 byte // filter. Thus, we give a little leeway and verify that the false positive // rate is no more than 5%. - ASSERT_LE(false_positives, 5); + EXPECT_LE(false_positives, 5); } } // namespace diff --git a/cpp/core/internal/mediums/bluetooth_classic.cc b/cpp/core/internal/mediums/bluetooth_classic.cc index c49348c5..63e8df68 100644 --- a/cpp/core/internal/mediums/bluetooth_classic.cc +++ b/cpp/core/internal/mediums/bluetooth_classic.cc @@ -1,466 +1,386 @@ #include "core/internal/mediums/bluetooth_classic.h" +#include +#include #include #include "core/internal/mediums/uuid.h" -#include "platform/synchronized.h" +#include "platform/public/logging.h" +#include "platform/public/mutex_lock.h" namespace location { namespace nearby { namespace connections { -template -const std::int32_t BluetoothClassic::kMaxConcurrentAcceptLoops = 5; +BluetoothClassic::BluetoothClassic(BluetoothRadio& radio) : radio_(radio) {} -template -BluetoothClassic::BluetoothClassic( - Ptr> bluetooth_radio) - : lock_(Platform::createLock()), - bluetooth_radio_(bluetooth_radio), - bluetooth_adapter_(Platform::createBluetoothAdapter()), - bluetooth_classic_medium_(Platform::createBluetoothClassicMedium()), - scan_info_(), - original_scan_mode_(BluetoothAdapter::ScanMode::UNKNOWN), - original_device_name_(), - accept_loops_thread_pool_( - Platform::createMultiThreadExecutor(kMaxConcurrentAcceptLoops)), - bluetooth_server_sockets_() {} - -template -BluetoothClassic::~BluetoothClassic() { - stopDiscovery(); - for (BluetoothServerSocketMap::iterator it = - bluetooth_server_sockets_.begin(); - it != bluetooth_server_sockets_.end(); ++it) { - stopAcceptingConnections(it->first); +BluetoothClassic::~BluetoothClassic() { + // Destructor is not taking locks, but methods it is calling are. + StopDiscovery(); + while (!server_sockets_.empty()) { + StopAcceptingConnections(server_sockets_.begin()->first); } - turnOffDiscoverability(); + TurnOffDiscoverability(); // All the AcceptLoopRunnable objects in here should already have gotten an // opportunity to shut themselves down cleanly in the calls to - // stopAcceptingConnections() above. - accept_loops_thread_pool_->shutdown(); - - original_device_name_.destroy(); - scan_info_.destroy(); + // StopAcceptingConnections() above. + accept_loops_runner_.Shutdown(); } -template -bool BluetoothClassic::isAvailable() { - Synchronized s(lock_.get()); +bool BluetoothClassic::IsAvailable() const { + MutexLock lock(&mutex_); - return !bluetooth_classic_medium_.isNull() && !bluetooth_adapter_.isNull(); + return IsAvailableLocked(); } -template -bool BluetoothClassic::turnOnDiscoverability( - const string& device_name) { - Synchronized s(lock_.get()); +bool BluetoothClassic::IsAvailableLocked() const { + return medium_.IsValid() && adapter_.IsValid(); +} + +bool BluetoothClassic::TurnOnDiscoverability(const std::string& device_name) { + MutexLock lock(&mutex_); if (device_name.empty()) { - // TODO(ahlee): logger.atSevere().log("Refusing to turn on Bluetooth - // discoverability because a null deviceName was passed in."); + NEARBY_LOG(INFO, + "Refusing to turn on BT discoverability. Empty device name."); return false; } - if (!bluetooth_radio_->isEnabled()) { - // TODO(reznor): log.atSevere().log("Can't turn on Bluetooth discoverability - // because Bluetooth isn't enabled."); + if (!radio_.IsEnabled()) { + NEARBY_LOG(INFO, "Can't turn on BT discoverability. BT is off."); return false; } - if (!isAvailable()) { - // TODO(reznor): log.atSevere().log("Can't turn on Bluetooth discoverability - // because Bluetooth isn't available."); + if (!IsAvailableLocked()) { + NEARBY_LOG(INFO, "Can't turn on BT discoverability. BT is not available."); return false; } - if (isDiscoverable()) { - // TODO(reznor): log.atSevere().log("Refusing to turn on Bluetooth - // discoverability with device name %s because we're already discoverable - // with device name %s.", deviceName, bluetoothAdapter.getName()); + if (IsDiscoverable()) { + NEARBY_LOG(INFO, + "Refusing to turn on BT discoverability; new name='%s'; " + "current name='%s'", + device_name.c_str(), adapter_.GetName().c_str()); return false; } - if (!modifyDeviceName(device_name)) { - // TODO(reznor): log.atSevere().log("Failed to turn on Bluetooth - // discoverability because we couldn't set the device name to %s", - // deviceName); + if (!ModifyDeviceName(device_name)) { + NEARBY_LOG(INFO, + "Failed to turn on BT discoverability; " + "failed to set name to %s", + device_name.c_str()); return false; } - if (!modifyScanMode(BluetoothAdapter::ScanMode::CONNECTABLE_DISCOVERABLE)) { - // TODO(reznor): log.atSevere().log("Failed to turn on Bluetooth - // discoverability because we couldn't set the scan mode to %d", - // BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE); + if (!ModifyScanMode(ScanMode::kConnectableDiscoverable)) { + NEARBY_LOG(INFO, + "Failed to turn on BT discoverability; " + "failed to set scan_mode to %d", + ScanMode::kConnectableDiscoverable); // Don't forget to perform this rollback of the partial state changes we've // made til now. - restoreDeviceName(); + RestoreDeviceName(); return false; } - // TODO(reznor): log.atVerbose().log("Turned on Bluetooth discoverability with - // deviceName %s", deviceName); + NEARBY_LOG(INFO, "Turned on BT discoverability with device_name=%s", + device_name.c_str()); return true; } -template -void BluetoothClassic::turnOffDiscoverability() { - Synchronized s(lock_.get()); +bool BluetoothClassic::TurnOffDiscoverability() { + MutexLock lock(&mutex_); - if (!isDiscoverable()) { - // TODO(reznor): log.atDebug().log("Can't turn off Bluetooth discoverability - // because it was never turned on."); - return; + if (!IsDiscoverable()) { + NEARBY_LOG(INFO, "Can't turn off BT discoverability; it is already off"); + return false; } - restoreScanMode(); - restoreDeviceName(); + RestoreScanMode(); + RestoreDeviceName(); - // TODO(reznor): log.atVerbose().log("Turned Bluetooth discoverability off"); + NEARBY_LOG(INFO, "Turned Bluetooth discoverability off"); + return true; } -template -bool BluetoothClassic::isDiscoverable() const { - return ((!original_device_name_.isNull()) && - (BluetoothAdapter::ScanMode::CONNECTABLE_DISCOVERABLE == - bluetooth_adapter_->getScanMode())); +bool BluetoothClassic::IsDiscoverable() const { + return (!original_device_name_.empty() && + (adapter_.GetScanMode() == ScanMode::kConnectableDiscoverable)); } -template -bool BluetoothClassic::modifyDeviceName(const string& device_name) { - original_device_name_ = bluetooth_adapter_->getName(); +bool BluetoothClassic::ModifyDeviceName(const std::string& device_name) { + if (original_device_name_.empty()) { + original_device_name_ = adapter_.GetName(); + } - if (!bluetooth_adapter_->setName(device_name)) { - original_device_name_.destroy(); + return adapter_.SetName(device_name); +} + +bool BluetoothClassic::ModifyScanMode(ScanMode scan_mode) { + if (original_scan_mode_ == ScanMode::kUnknown) { + original_scan_mode_ = adapter_.GetScanMode(); + } + + if (!adapter_.SetScanMode(scan_mode)) { + original_scan_mode_ = ScanMode::kUnknown; return false; } return true; } -template -bool BluetoothClassic::modifyScanMode( - BluetoothAdapter::ScanMode::Value scan_mode) { - original_scan_mode_ = bluetooth_adapter_->getScanMode(); - - if (!bluetooth_adapter_->setScanMode(scan_mode)) { - original_scan_mode_ = BluetoothAdapter::ScanMode::UNKNOWN; +bool BluetoothClassic::RestoreScanMode() { + if (original_scan_mode_ == ScanMode::kUnknown || + !adapter_.SetScanMode(original_scan_mode_)) { + NEARBY_LOG(INFO, "Failed to restore original Bluetooth scan mode to %d", + original_scan_mode_); return false; } - return true; -} - -template -void BluetoothClassic::restoreScanMode() { - if (!bluetooth_adapter_->setScanMode(original_scan_mode_)) { - // TODO(reznor): log.atWarning().log("Failed to restore original Bluetooth - // scan mode to %d", originalScanMode); - } - // Regardless of whether or not we could actually restore the Bluetooth scan // mode, reset our relevant state. - original_scan_mode_ = BluetoothAdapter::ScanMode::UNKNOWN; + original_scan_mode_ = ScanMode::kUnknown; + return true; } -template -void BluetoothClassic::restoreDeviceName() { - if (!bluetooth_adapter_->setName(*original_device_name_)) { - // TODO(reznor): log.atWarning().log("Failed to restore original Bluetooth - // device name to %s", originalDeviceName); +bool BluetoothClassic::RestoreDeviceName() { + if (original_device_name_.empty() || + !adapter_.SetName(original_device_name_)) { + NEARBY_LOG(INFO, "Failed to restore original Bluetooth device name to %s", + original_device_name_.c_str()); + return false; } - - // Regardless of whether or not we could actually restore the Bluetooth device - // name, reset the marker that opens us up for business for the next time - // 'round. - original_device_name_.destroy(); + original_device_name_.clear(); + return true; } -template -bool BluetoothClassic::startDiscovery( - Ptr discovered_device_callback) { - Synchronized s(lock_.get()); +bool BluetoothClassic::StartDiscovery(DiscoveredDeviceCallback callback) { + MutexLock lock(&mutex_); - if (discovered_device_callback.isNull()) { - // TODO(reznor): log.atSevere().log("Refusing to start discovery of - // Bluetooth devices because a null discoveredDeviceCallback was passed - // in."); - return false; - } - // Avoid leaks. - ScopedPtr> scoped_discovered_device_callback( - discovered_device_callback); - - if (!bluetooth_radio_->isEnabled()) { - // TODO(reznor): log.atSevere().log("Can't discover Bluetooth devices - // because Bluetooth isn't enabled."); + if (!radio_.IsEnabled()) { + NEARBY_LOG(INFO, "Can't discover BT devices because BT isn't enabled."); return false; } - if (!isAvailable()) { - // TODO(reznor): log.atSevere().log("Can't discover Bluetooth devices - // because Bluetooth isn't available."); + if (!IsAvailableLocked()) { + NEARBY_LOG(INFO, "Can't discover BT devices because BT isn't available."); return false; } - if (isDiscovering()) { - // TODO(reznor): log.atSevere().log("Refusing to start discovery of - // Bluetooth devices because another discovery is already in-progress."); + if (IsDiscovering()) { + NEARBY_LOG(INFO, + "Refusing to start discovery of BT devices because another " + "discovery is already in-progress."); return false; } - // Avoid leaks. - ScopedPtr> - scoped_bluetooth_discovery_callback(new BluetoothDiscoveryCallback( - scoped_discovered_device_callback.get())); - - if (!bluetooth_classic_medium_->startDiscovery( - scoped_bluetooth_discovery_callback.get())) { - // TODO(reznor): log.atSevere().log("Failed to start discovery of Bluetooth - // devices."); + if (!medium_.StartDiscovery(callback)) { + NEARBY_LOG(INFO, "Failed to start discovery of BT devices."); return false; } // Mark the fact that we're currently performing a Bluetooth scan. - scan_info_ = - MakePtr(new ScanInfo(scoped_discovered_device_callback.release(), - scoped_bluetooth_discovery_callback.release())); + scan_info_.valid = true; + return true; } -template -void BluetoothClassic::stopDiscovery() { - Synchronized s(lock_.get()); +bool BluetoothClassic::StopDiscovery() { + MutexLock lock(&mutex_); - if (!isDiscovering()) { - // TODO(reznor): log.atDebug().log("Can't stop discovery of Bluetooth - // devices because it never started."); - return; + if (!IsDiscovering()) { + NEARBY_LOG(INFO, + "Can't stop discovery of BT devices because it never started."); + return false; } - if (!bluetooth_classic_medium_->stopDiscovery()) { - // TODO(reznor): log.atWarning().log("Failed to stop discovery of Bluetooth - // devices."); + if (!medium_.StopDiscovery()) { + NEARBY_LOG(INFO, "Failed to stop discovery of Bluetooth devices."); + return false; } - // Regardless of whether or not stopDiscovery() succeeded, destroy scan_info_ - // to: - // - // a) Avoid a leak. - // b) Mark the fact that we're no longer performing a Bluetooth discovery. - scan_info_.destroy(); + + scan_info_.valid = false; + return true; } -template -bool BluetoothClassic::isDiscovering() const { - return !scan_info_.isNull(); -} +bool BluetoothClassic::IsDiscovering() const { return scan_info_.valid; } -template -class AcceptLoopRunnable : public Runnable { - public: - AcceptLoopRunnable( - Ptr::AcceptedConnectionCallback> - accepted_connection_callback, - Ptr listening_socket, const string& service_name) - : accepted_connection_callback_(accepted_connection_callback), - listening_socket_(listening_socket), - service_name_(service_name) {} +bool BluetoothClassic::StartAcceptingConnections( + const std::string& service_name, AcceptedConnectionCallback callback) { + MutexLock lock(&mutex_); - void run() override { - while (true) { - ExceptionOr> bluetooth_socket = - listening_socket_->accept(); - if (!bluetooth_socket.ok()) { - if (Exception::IO == bluetooth_socket.exception()) { - Utils::closeSocket(listening_socket_, "Bluetooth", service_name_); - } - break; - } - - accepted_connection_callback_->onConnectionAccepted( - bluetooth_socket.result()); - } - } - - private: - ScopedPtr< - Ptr::AcceptedConnectionCallback>> - accepted_connection_callback_; - Ptr listening_socket_; - const string service_name_; -}; - -template -bool BluetoothClassic::startAcceptingConnections( - const string& service_name, - Ptr accepted_connection_callback) { - Synchronized s(lock_.get()); - - // Avoid leaks. - ScopedPtr> - scoped_accepted_connection_callback(accepted_connection_callback); - if (scoped_accepted_connection_callback.isNull() || service_name.empty()) { - // TODO(reznor): log.atSevere().log("Refusing to start accepting Bluetooth - // connections because at least one of serviceName or - // acceptedConnectionCallback is null."); + if (service_name.empty()) { + NEARBY_LOG( + INFO, + "Refusing to start accepting BT connections; service name is empty."); return false; } - if (!bluetooth_radio_->isEnabled()) { - // TODO(reznor): log.atSevere().log("Can't create Bluetooth server socket - // for %s because Bluetooth isn't enabled.", serviceName); + if (!radio_.IsEnabled()) { + NEARBY_LOG(INFO, + "Can't create BT server socket [service=%s]; BT is disabled.", + service_name.c_str()); return false; } - if (!isAvailable()) { - // TODO(reznor): log.atSevere().log("Can't start accepting BLuetooth - // connections for %s because Bluetooth isn't available.", serviceName); + if (!IsAvailableLocked()) { + NEARBY_LOG( + INFO, + "Can't start accepting BT connections [service=%s]; BT not available.", + service_name.c_str()); return false; } - if (isAcceptingConnections(service_name)) { - // TODO(reznor): log.atSevere().log("Refusing to start accepting Bluetooth - // connections for %s because a Bluetooth server is already in-progress for - // that service name.", serviceName); + if (IsAcceptingConnectionsLocked(service_name)) { + NEARBY_LOG(INFO, + "Refusing to start accepting BT connections [service=%s]; BT " + "server is already in-progress with the same name.", + service_name.c_str()); return false; } - ExceptionOr> listening_socket = - bluetooth_classic_medium_->listenForService( - service_name, generateUUIDFromString(service_name)); - if (!listening_socket.ok()) { - if (Exception::IO == listening_socket.exception()) { - // TODO(reznor): log.atSevere().withCause(e).log("Failed to start - // accepting Bluetooth connections for %s.", serviceName); - return false; - } + BluetoothServerSocket socket = medium_.ListenForService( + service_name, GenerateUuidFromString(service_name)); + if (!socket.IsValid()) { + NEARBY_LOG(INFO, "Failed to start accepting Bluetooth connections for %s.", + service_name.c_str()); + return false; } - // Start the accept loop on a dedicated thread - this stays alive and - // listening for new incoming connections until stopAcceptingConnections() is - // invoked. - accept_loops_thread_pool_->execute(MakePtr(new AcceptLoopRunnable( - scoped_accepted_connection_callback.release(), listening_socket.result(), - service_name))); - // Mark the fact that there's an in-progress Bluetooth server accepting // connections. - bluetooth_server_sockets_.insert( - std::make_pair(service_name, listening_socket.result())); + auto owned_socket = + server_sockets_.emplace(service_name, std::move(socket)).first->second; + + // Start the accept loop on a dedicated thread - this stays alive and + // listening for new incoming connections until StopAcceptingConnections() is + // invoked. + accept_loops_runner_.Execute([callback = std::move(callback), + server_socket = std::move(owned_socket), + service_name]() mutable { + while (true) { + BluetoothSocket client_socket = server_socket.Accept(); + if (!client_socket.IsValid()) { + server_socket.Close(); + break; + } + + callback.accepted_cb(std::move(client_socket)); + } + }); + return true; } -template -bool BluetoothClassic::isAcceptingConnections( - const string& service_name) { - Synchronized s(lock_.get()); +bool BluetoothClassic::IsAcceptingConnections(const std::string& service_name) { + MutexLock lock(&mutex_); - return bluetooth_server_sockets_.find(service_name) != - bluetooth_server_sockets_.end(); + return IsAcceptingConnectionsLocked(service_name); } -template -void BluetoothClassic::stopAcceptingConnections( - const string& service_name) { - Synchronized s(lock_.get()); +bool BluetoothClassic::IsAcceptingConnectionsLocked( + const std::string& service_name) { + return server_sockets_.find(service_name) != server_sockets_.end(); +} + +bool BluetoothClassic::StopAcceptingConnections( + const std::string& service_name) { + MutexLock lock(&mutex_); if (service_name.empty()) { - // TODO(ahlee): logger.atSevere().log("Unable to stop accepting Bluetooth - // connections because the serviceName is empty."); - return; + NEARBY_LOG(INFO, + "Unable to stop accepting BT connections because the " + "service_name is empty."); + return false; } - if (!isAcceptingConnections(service_name)) { - // TODO(reznor): log.atDebug().log("Can't stop accepting Bluetooth - // connections for %s because it was never started.", serviceName); - return; + const auto& it = server_sockets_.find(service_name); + if (it == server_sockets_.end()) { + NEARBY_LOG(INFO, + "Can't stop accepting BT connections for %s because it was " + "never started.", + service_name.c_str()); + return false; } // Closing the BluetoothServerSocket will kick off the suicide of the thread // in accept_loops_thread_pool_ that blocks on BluetoothServerSocket.accept(). // That may take some time to complete, but there's no particular reason to // wait around for it. - BluetoothServerSocketMap::iterator listening_socket_iter = - bluetooth_server_sockets_.find(service_name); + auto item = server_sockets_.extract(it); // Store a handle to the BluetoothServerSocket, so we can use it after - // removing the entry from bluetooth_server_sockets_; making it scoped + // removing the entry from server_sockets_; making it scoped // is a bonus that takes care of deallocation before we leave this method. - ScopedPtr> scoped_listening_socket( - listening_socket_iter->second); + BluetoothServerSocket& listening_socket = item.mapped(); // Regardless of whether or not we fail to close the existing - // BluetoothServerSocket, remove it from bluetooth_server_sockets_ so that it + // BluetoothServerSocket, remove it from server_sockets_ so that it // frees up this service for another round. - bluetooth_server_sockets_.erase(listening_socket_iter); // Finally, close the BluetoothServerSocket. - Exception::Value e = scoped_listening_socket->close(); - if (Exception::NONE != e) { - if (Exception::IO == e) { - // TODO(reznor): log.atSevere().withCause(e).log("Failed to close - // Bluetooth server socket for %s.", serviceName); - } + if (!listening_socket.Close().Ok()) { + NEARBY_LOG(INFO, "Failed to close BT server socket for %s.", + service_name.c_str()); + return false; } + + return true; } -template -Ptr BluetoothClassic::connect( - Ptr bluetooth_device, const string& service_name) { - Synchronized s(lock_.get()); +BluetoothSocket BluetoothClassic::Connect(BluetoothDevice& bluetooth_device, + const std::string& service_name) { + MutexLock lock(&mutex_); + NEARBY_LOG(INFO, "BluetoothClassic::Connect: device=%p", &bluetooth_device); + // Socket to return. To allow for NRVO to work, it has to be a single object. + BluetoothSocket socket; - if (bluetooth_device.isNull() || service_name.empty()) { - // TODO(reznor): log.atSevere().log("Refusing to create client Bluetooth - // socket because at least one of bluetoothDevice or serviceName is null."); - return Ptr(); + if (service_name.empty()) { + NEARBY_LOG( + INFO, + "Refusing to create client BT socket because service_name is empty."); + return socket; } - if (!bluetooth_radio_->isEnabled()) { - // TODO(reznor): log.atSevere().log("Can't create client Bluetooth socket to - // %s because Bluetooth isn't enabled.", bluetoothSocketName); - return Ptr(); + if (!radio_.IsEnabled()) { + NEARBY_LOG(INFO, + "Can't create client BT socket [service=%s]: BT isn't enabled.", + service_name.c_str()); + return socket; } - if (!isAvailable()) { - // TODO(reznor): log.atSevere().log("Can't create client Bluetooth socket to - // %s because Bluetooth isn't available.", bluetoothSocketName); - return Ptr(); + if (!IsAvailableLocked()) { + NEARBY_LOG( + INFO, "Can't create client BT socket [service=%s]; BT isn't available.", + service_name.c_str()); + return socket; } - // WARNING WARNING WARNING - // - // This block deviates from the corresponding Java code. - // - // In Java, we pause an in-progress discovery before attempting this - // connection, and then resume it after, but the memory management of the - // DiscoveredDeviceCallback is complicated in C++, and would need a severe - // deviation from the Java code, so we're choosing the lesser of 2 evils, and - // introducing this (simplifying) deviation instead -- also, this deviation is - // fairly inconsequential since we don't yet have a use-case that needs a - // device that: - // - // a) uses the C++ code, - // b) has Bluetooth Classic support, and - // c) plays the role of Discoverer. - ExceptionOr> bluetooth_socket = - bluetooth_classic_medium_->connectToService( - bluetooth_device, generateUUIDFromString(service_name)); - if (!bluetooth_socket.ok()) { - if (Exception::IO == bluetooth_socket.exception()) { - // TODO(reznor): log.atSevere().log("Failed to connect via Bluetooth - // socket to %s.", bluetoothSocketName); - } - return Ptr(); + socket = medium_.ConnectToService(bluetooth_device, + GenerateUuidFromString(service_name)); + if (!socket.IsValid()) { + NEARBY_LOG(INFO, "Failed to Connect via BT [service=%s]", + service_name.c_str()); } - return bluetooth_socket.result(); + return socket; } -template -string BluetoothClassic::generateUUIDFromString(const string& data) { - return UUID(data).str(); +BluetoothDevice BluetoothClassic::GetRemoteDevice( + const std::string& mac_address) { + MutexLock lock(&mutex_); + return medium_.GetRemoteDevice(mac_address); +} + +std::string BluetoothClassic::GetMacAddress() const { + MutexLock lock(&mutex_); + return medium_.GetMacAddress(); +} + +std::string BluetoothClassic::GenerateUuidFromString(const std::string& data) { + return std::string(Uuid(data)); } } // namespace connections diff --git a/cpp/core/internal/mediums/bluetooth_classic.h b/cpp/core/internal/mediums/bluetooth_classic.h index dddf3993..18262767 100644 --- a/cpp/core/internal/mediums/bluetooth_classic.h +++ b/cpp/core/internal/mediums/bluetooth_classic.h @@ -2,168 +2,182 @@ #define CORE_INTERNAL_MEDIUMS_BLUETOOTH_CLASSIC_H_ #include -#include +#include #include "core/internal/mediums/bluetooth_radio.h" -#include "core/internal/mediums/utils.h" -#include "platform/api/bluetooth_adapter.h" -#include "platform/api/bluetooth_classic.h" -#include "platform/api/lock.h" -#include "platform/api/multi_thread_executor.h" -#include "platform/byte_array.h" -#include "platform/port/string.h" -#include "platform/ptr.h" -#include "platform/runnable.h" +#include "core/listeners.h" +#include "platform/base/byte_array.h" +#include "platform/public/bluetooth_adapter.h" +#include "platform/public/bluetooth_classic.h" +#include "platform/public/multi_thread_executor.h" +#include "platform/public/mutex.h" +#include "absl/container/flat_hash_map.h" namespace location { namespace nearby { namespace connections { -template class BluetoothClassic { public: - explicit BluetoothClassic(Ptr> bluetooth_radio); - ~BluetoothClassic(); - - bool isAvailable(); - - bool turnOnDiscoverability(const string& device_name); - void turnOffDiscoverability(); - - // Callback that is invoked when a nearby Bluetooth device is discovered. - class DiscoveredDeviceCallback { - public: - virtual ~DiscoveredDeviceCallback() {} - - virtual void onDeviceDiscovered(Ptr device) = 0; - virtual void onDeviceNameChanged(Ptr device) = 0; - virtual void onDeviceLost(Ptr device) = 0; - }; - - bool startDiscovery(Ptr discovered_device_callback); - void stopDiscovery(); + using DiscoveredDeviceCallback = BluetoothClassicMedium::DiscoveryCallback; + using ScanMode = BluetoothAdapter::ScanMode; // Callback that is invoked when a new connection is accepted. - class AcceptedConnectionCallback { - public: - virtual ~AcceptedConnectionCallback() {} - - virtual void onConnectionAccepted(Ptr socket) = 0; + struct AcceptedConnectionCallback { + std::function accepted_cb = + DefaultCallback(); }; - bool startAcceptingConnections( - const string& service_name, - Ptr accepted_connection_callback); - bool isAcceptingConnections(const string& service_name); - void stopAcceptingConnections(const string& service_name); + explicit BluetoothClassic(BluetoothRadio& bluetooth_radio); + ~BluetoothClassic(); - Ptr connect(Ptr bluetooth_device, - const string& service_name); + // Returns true, if BT communications are supported by a platform. + bool IsAvailable() const ABSL_LOCKS_EXCLUDED(mutex_); + + // Sets custom device name, and then enables BT discoverable mode. + // Returns true, if name and scan mode are successfully set, and false + // otherwise. + // Called by server. + bool TurnOnDiscoverability(const std::string& device_name) + ABSL_LOCKS_EXCLUDED(mutex_); + + // Disables BT discoverability, and restores scan mode and device name to + // what they were before the call to TurnOnDiscoverability(). + // Returns false if no successful call TurnOnDiscoverability() was previously + // made, otherwise returns true. + // Called by server. + bool TurnOffDiscoverability() ABSL_LOCKS_EXCLUDED(mutex_); + + // Enables BT discovery mode. Will report any discoverable devices in range + // through a callback. + // Returns true, if discovery mode was enabled, false otherwise. + // Called by client. + bool StartDiscovery(DiscoveredDeviceCallback callback) + ABSL_LOCKS_EXCLUDED(mutex_); + + // Disables BT discovery mode. + // Returns true, if discovery mode was previously enabled, false otherwise. + // Called by client. + bool StopDiscovery() ABSL_LOCKS_EXCLUDED(mutex_); + + // Starts a worker thread, creates a BT server socket, associates it with a + // service name; in a worker thread repeatedly calls ServerSocket::Accept(). + // Any connected sockets returned from Accept() are passed to a callback. + // Returns true, if server socket was successfully created, false otherwise. + // Called by server. + bool StartAcceptingConnections(const std::string& service_name, + AcceptedConnectionCallback callback) + ABSL_LOCKS_EXCLUDED(mutex_); + + // Returns true, if object is currently running a Accept() loop. + bool IsAcceptingConnections(const std::string& service_name) + ABSL_LOCKS_EXCLUDED(mutex_); + + // Closes server socket corresponding to a service name. This automatically + // terminates Accept() loop, if it were running. + // Called by server. + bool StopAcceptingConnections(const std::string& service_name) + ABSL_LOCKS_EXCLUDED(mutex_); + + // Returns true if this object owns a valid platform implementation. + bool IsMediumValid() const ABSL_LOCKS_EXCLUDED(mutex_) { + MutexLock lock(&mutex_); + return medium_.IsValid(); + } + + // Returns true if this object has a valid BluetoothAdapter reference. + bool IsAdapterValid() const ABSL_LOCKS_EXCLUDED(mutex_) { + MutexLock lock(&mutex_); + return adapter_.IsValid(); + } + + // Establishes connection to BT service that was might be started on another + // device with StartAcceptingConnections() using the same service_name. + // Blocks until connection is established, or server-side is terminated. + // Returns socket instance. On success, BluetoothSocket.IsValid() return true. + // Called by client. + BluetoothSocket Connect(BluetoothDevice& bluetooth_device, + const std::string& service_name) + ABSL_LOCKS_EXCLUDED(mutex_); + + std::string GetMacAddress() const ABSL_LOCKS_EXCLUDED(mutex_); + + BluetoothDevice GetRemoteDevice(const std::string& mac_address) + ABSL_LOCKS_EXCLUDED(mutex_); private: - class BluetoothDiscoveryCallback - : public BluetoothClassicMedium::DiscoveryCallback { - public: - explicit BluetoothDiscoveryCallback( - Ptr discovered_device_callback) - : discovered_device_callback_(discovered_device_callback) {} - ~BluetoothDiscoveryCallback() override { - // Nothing to do. - } - - void onDeviceDiscovered(Ptr bluetooth_device) override { - discovered_device_callback_->onDeviceDiscovered(bluetooth_device); - } - void onDeviceNameChanged(Ptr bluetooth_device) override { - discovered_device_callback_->onDeviceNameChanged(bluetooth_device); - } - void onDeviceLost(Ptr bluetooth_device) override { - discovered_device_callback_->onDeviceLost(bluetooth_device); - } - - private: - // This could well have been a ScopedPtr, with BluetoothDiscoveryCallback in - // turn being owned by ScanInfo (and it would have been cleaner overall, - // since the chain of wrapped callbacks starting from - // BluetoothDiscoveryCallback would then destruct like a stack of dominoes - // falling, triggered by the destruction of ScanInfo), but we instead give - // ownership of this DiscoveredDeviceCallback *and* - // BluetoothDiscoveryCallback to ScanInfo, to maintain compatibility with - // the Java code. - Ptr discovered_device_callback_; - }; - struct ScanInfo { - ScanInfo(Ptr discovered_device_callback, - Ptr bluetooth_discovery_callback) - : discovered_device_callback(discovered_device_callback), - bluetooth_discovery_callback(bluetooth_discovery_callback) {} - ~ScanInfo() { - // Nothing to do (the ScopedPtr members take care of themselves). - } - - // Stores the DiscoveredDeviceCallback passed in to startDiscovery() by - // clients so that we can internally stop and start Bluetooth scans - // transparently as needed (for example, when a call to connect() is - // invoked). - ScopedPtr> discovered_device_callback; - // The ordering of bluetooth_discovery_callback_ coming after - // discovered_device_callback_ is very deliberate -- - // bluetooth_discovery_callback_ contains a reference to - // discovered_device_callback_, so it should be destroyed first. - ScopedPtr> bluetooth_discovery_callback; + bool valid = false; }; - static string generateUUIDFromString(const string& data); + static constexpr int kMaxConcurrentAcceptLoops = 5; - static const std::int32_t kMaxConcurrentAcceptLoops; + // Constructs UUID object from arbitrary string, using MD5 hash, and then + // converts UUID to a readable UUID string and returns it. + static std::string GenerateUuidFromString(const std::string& data); - bool isDiscoverable() const; - bool modifyDeviceName(const string& device_name); - bool modifyScanMode(BluetoothAdapter::ScanMode::Value scan_mode); - void restoreScanMode(); - void restoreDeviceName(); - bool isDiscovering() const; + // Same as IsAvailable(), but must be called with mutex_ held. + bool IsAvailableLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - // ------------ GENERAL ------------ + // Same as IsAcceptingConnections(), but must be called with mutex_ held. + bool IsAcceptingConnectionsLocked(const std::string& service_name) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - ScopedPtr> lock_; + // Returns true, if discoverability is enabled with TurnOnDiscoverability(). + bool IsDiscoverable() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - // ------------ CORE BLUETOOTH ------------ + // Assignes a different name to BT adapter. + // Returns true if successful. Stores original device name. + bool ModifyDeviceName(const std::string& device_name) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - Ptr> bluetooth_radio_; - ScopedPtr> bluetooth_adapter_; - // The underlying, per-platform implementation. - ScopedPtr> bluetooth_classic_medium_; + // Changes current scan mode. This is an implementation of + // TurnDiscoveradility() method. Stores original scan mode. + bool ModifyScanMode(ScanMode scan_mode) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - // ------------ DISCOVERY ------------ + // Restores original device name (the one before the very first call to + // ModifyDeviceName()). Returns true if successful. + bool RestoreScanMode() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Restores original device scan mode (the one before the very first call to + // ModifyScanMode()). Returns true if successful. + bool RestoreDeviceName() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Returns true if device is currently in discovery mode. + bool IsDiscovering() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + mutable Mutex mutex_; + BluetoothRadio& radio_ ABSL_GUARDED_BY(mutex_); + BluetoothAdapter& adapter_ ABSL_GUARDED_BY(mutex_){ + radio_.GetBluetoothAdapter()}; + BluetoothClassicMedium medium_ ABSL_GUARDED_BY(mutex_){adapter_}; // A bundle of state required to do a Bluetooth Classic scan. When non-null, // we are currently performing a Bluetooth scan. - Ptr scan_info_; - - // ------------ ADVERTISING ------------ + ScanInfo scan_info_ ABSL_GUARDED_BY(mutex_); // The original scan mode (that controls visibility to scanners) of the device // before we modified it. Restored when we stop advertising. - BluetoothAdapter::ScanMode::Value original_scan_mode_; - // The original Bluetooth device name, before we modified it. If non-null, we + ScanMode original_scan_mode_ ABSL_GUARDED_BY(mutex_) = ScanMode::kUnknown; + + // The original Bluetooth device name, before we modified it. If non-empty, we // are currently Bluetooth discoverable. Restored when we stop advertising. - Ptr original_device_name_; + std::string original_device_name_ ABSL_GUARDED_BY(mutex_); + // A thread pool dedicated to running all the accept loops from - // startAcceptingConnections(). - ScopedPtr> - accept_loops_thread_pool_; - // A map of service name -> ServerSocket. While this map is non-empty, we + // StartAcceptingConnections(). + MultiThreadExecutor accept_loops_runner_{kMaxConcurrentAcceptLoops}; + + // A map of service Name -> ServerSocket. If map is non-empty, we // are currently listening for incoming connections. - typedef std::map> BluetoothServerSocketMap; - BluetoothServerSocketMap bluetooth_server_sockets_; + // BluetoothServerSocket instances are used from accept_loops_runner_, + // and thus require pointer stability. + absl::flat_hash_map server_sockets_ + ABSL_GUARDED_BY(mutex_); }; } // namespace connections } // namespace nearby } // namespace location -#include "core/internal/mediums/bluetooth_classic.cc" - #endif // CORE_INTERNAL_MEDIUMS_BLUETOOTH_CLASSIC_H_ diff --git a/cpp/core_v2/internal/mediums/bluetooth_classic_test.cc b/cpp/core/internal/mediums/bluetooth_classic_test.cc similarity index 95% rename from cpp/core_v2/internal/mediums/bluetooth_classic_test.cc rename to cpp/core/internal/mediums/bluetooth_classic_test.cc index f9a253c0..7294c131 100644 --- a/cpp/core_v2/internal/mediums/bluetooth_classic_test.cc +++ b/cpp/core/internal/mediums/bluetooth_classic_test.cc @@ -1,13 +1,13 @@ -#include "core_v2/internal/mediums/bluetooth_classic.h" +#include "core/internal/mediums/bluetooth_classic.h" #include -#include "core_v2/internal/mediums/bluetooth_radio.h" -#include "platform_v2/base/medium_environment.h" -#include "platform_v2/public/bluetooth_classic.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/logging.h" -#include "platform_v2/public/system_clock.h" +#include "core/internal/mediums/bluetooth_radio.h" +#include "platform/base/medium_environment.h" +#include "platform/public/bluetooth_classic.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/logging.h" +#include "platform/public/system_clock.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/time/time.h" diff --git a/cpp/core/internal/mediums/bluetooth_radio.cc b/cpp/core/internal/mediums/bluetooth_radio.cc index 9edaa777..ca0e2f23 100644 --- a/cpp/core/internal/mediums/bluetooth_radio.cc +++ b/cpp/core/internal/mediums/bluetooth_radio.cc @@ -1,117 +1,101 @@ #include "core/internal/mediums/bluetooth_radio.h" -#include "platform/exception.h" +#include "platform/base/exception.h" +#include "platform/public/logging.h" +#include "platform/public/system_clock.h" namespace location { namespace nearby { namespace connections { -template -std::int64_t BluetoothRadio::kPauseBetweenToggleDurationMillis = 3000; +constexpr absl::Duration BluetoothRadio::kPauseBetweenToggle; -template -BluetoothRadio::BluetoothRadio() - : bluetooth_adapter_(Platform::createBluetoothAdapter()), - thread_utils_(Platform::createThreadUtils()), - originally_enabled_() { - if (bluetooth_adapter_.isNull()) { - // TODO(reznor): log.atSevere().log("Failed to retrieve default - // BluetoothAdapter, Bluetooth is unsupported."); +BluetoothRadio::BluetoothRadio() { + if (!IsAdapterValid()) { + NEARBY_LOG(ERROR, "Bluetooth adapter is not valid: BT is not supported"); } } -template -BluetoothRadio::~BluetoothRadio() { +BluetoothRadio::~BluetoothRadio() { // We never enabled Bluetooth, nothing to do. - if (originally_enabled_.isNull()) { + if (!ever_saved_state_.Get()) { + NEARBY_LOG(INFO, "BT adapter was not used. Not touching HW."); return; } - // Make sure we cleanup the one non-ScopedPtr member before we leave the - // destructor. - ScopedPtr > scoped_originally_enabled(originally_enabled_); - // Toggle Bluetooth regardless of our original state. Some devices/chips can // start to freak out after some time (e.g. b/37775337), and this helps to // ensure BT resets properly. - toggle(); + NEARBY_LOG(INFO, "Toggle BT adapter state before releasing adapter."); + Toggle(); - if (!setBluetoothState(originally_enabled_->get())) { - // TODO(reznor): log.atWarning().log("Failed to turn Bluetooth back to its - // original state."); + NEARBY_LOG(INFO, "Bring BT adapter to original state"); + if (!SetBluetoothState(originally_enabled_.Get())) { + NEARBY_LOG(INFO, "Failed to restore BT adapter original state."); } } -template -bool BluetoothRadio::enable() { - if (!saveOriginalState()) { +bool BluetoothRadio::Enable() { + if (!SaveOriginalState()) { return false; } - return setBluetoothState(true); + return SetBluetoothState(true); } -template -bool BluetoothRadio::disable() { - if (!saveOriginalState()) { +bool BluetoothRadio::Disable() { + if (!SaveOriginalState()) { return false; } - return setBluetoothState(false); + return SetBluetoothState(false); } -template -bool BluetoothRadio::isEnabled() { - return !bluetooth_adapter_.isNull() && isInDesiredState(true); +bool BluetoothRadio::IsEnabled() const { + return IsAdapterValid() && IsInDesiredState(true); } -template -void BluetoothRadio::toggle() { - if (!saveOriginalState()) { - return; +bool BluetoothRadio::Toggle() { + if (!SaveOriginalState()) { + return false; } - if (!setBluetoothState(false)) { - // TODO(reznor): log.atWarning().log("Failed to turn Bluetooth off while - // toggling state."); + if (!SetBluetoothState(false)) { + NEARBY_LOG(INFO, "BT Toggle: Failed to turn BT off."); + return false; } - if (Exception::INTERRUPTED == - thread_utils_->sleep(kPauseBetweenToggleDurationMillis)) { - // TODO(reznor): log.atSevere().withCause(e).log("Interrupted while waiting - // in between a Bluetooth toggle."); - return; + if (SystemClock::Sleep(kPauseBetweenToggle).Raised(Exception::kInterrupted)) { + NEARBY_LOG(INFO, "BT Toggle: interrupted before turing on."); + return false; } - if (!setBluetoothState(true)) { - // TODO(reznor): log.atWarning().log("Failed to turn Bluetooth on while - // toggling state."); + if (!SetBluetoothState(true)) { + NEARBY_LOG(INFO, "BT Toggle: Failed to turn BT on."); + return false; } + + return true; } -template -bool BluetoothRadio::setBluetoothState(bool enable) { - return bluetooth_adapter_->setStatus( - enable ? BluetoothAdapter::Status::ENABLED - : BluetoothAdapter::Status::DISABLED); +bool BluetoothRadio::SetBluetoothState(bool enable) { + return bluetooth_adapter_.SetStatus( + enable ? BluetoothAdapter::Status::kEnabled + : BluetoothAdapter::Status::kDisabled); } -template -bool BluetoothRadio::isInDesiredState(bool should_be_enabled) const { - return ((should_be_enabled && bluetooth_adapter_->isEnabled()) || - (!should_be_enabled && !bluetooth_adapter_->isEnabled())); +bool BluetoothRadio::IsInDesiredState(bool should_be_enabled) const { + return bluetooth_adapter_.IsEnabled() == should_be_enabled; } -template -bool BluetoothRadio::saveOriginalState() { - if (bluetooth_adapter_.isNull()) { +bool BluetoothRadio::SaveOriginalState() { + if (!IsAdapterValid()) { return false; } // If we haven't saved the original state of the radio, save it. - if (originally_enabled_.isNull()) { - originally_enabled_ = - Platform::createAtomicBoolean(bluetooth_adapter_->isEnabled()); + if (!ever_saved_state_.Set(true)) { + originally_enabled_.Set(bluetooth_adapter_.IsEnabled()); } return true; diff --git a/cpp/core/internal/mediums/bluetooth_radio.h b/cpp/core/internal/mediums/bluetooth_radio.h index 14dd611b..a1f7211b 100644 --- a/cpp/core/internal/mediums/bluetooth_radio.h +++ b/cpp/core/internal/mediums/bluetooth_radio.h @@ -3,20 +3,21 @@ #include -#include "platform/api/atomic_boolean.h" -#include "platform/api/bluetooth_adapter.h" -#include "platform/api/thread_utils.h" -#include "platform/ptr.h" +#include "platform/public/atomic_boolean.h" +#include "platform/public/bluetooth_adapter.h" +#include "absl/time/clock.h" namespace location { namespace nearby { namespace connections { // Provides the operations that can be performed on the Bluetooth radio. -template class BluetoothRadio { public: BluetoothRadio(); + BluetoothRadio(BluetoothRadio&&) = default; + BluetoothRadio& operator=(BluetoothRadio&&) = default; + // Reverts the Bluetooth radio to its original state. ~BluetoothRadio(); @@ -26,44 +27,54 @@ class BluetoothRadio { // this class. // // Returns true if enabled successfully. - bool enable(); + bool Enable(); + // Disables Bluetooth. // // Returns true if disabled successfully. - bool disable(); - // Returns true if the Bluetooth radio is currently enabled. - bool isEnabled(); + bool Disable(); - void toggle(); + // Returns true if the Bluetooth radio is currently enabled. + bool IsEnabled() const; + + // Turn BT radio Off, delay for kPauseBetweenToggle and then turn it On. + // This will block calling thread for at least kPauseBetweenToggle duration. + bool Toggle(); + + // Returns result of BluetoothAdapter::IsValid() for private adapter instance. + bool IsAdapterValid() const { + return bluetooth_adapter_.IsValid(); + } + + BluetoothAdapter& GetBluetoothAdapter() { + return bluetooth_adapter_; + } private: - static std::int64_t kPauseBetweenToggleDurationMillis; + static constexpr absl::Duration kPauseBetweenToggle = absl::Seconds(3); - bool setBluetoothState(bool enable); - bool isInDesiredState(bool should_be_enabled) const; + bool SetBluetoothState(bool enable); + bool IsInDesiredState(bool should_be_enabled) const; // To be called in enable(), disable(), and toggle(). This will remember the // original state of the radio before any radio state has been modified. // Returns false if Bluetooth doesn't exist on the device and the state cannot // be obtained. - bool saveOriginalState(); + bool SaveOriginalState(); + + // BluetoothAdapter::IsValid() will return false if BT is not supported. + BluetoothAdapter bluetooth_adapter_; - // Null if the device does not support Bluetooth. - ScopedPtr> bluetooth_adapter_; - ScopedPtr> thread_utils_; // The Bluetooth radio's original state, before we modified it. True if - // originally enabled, false if originally disabled, null if we never modified - // the radio state. We restore the radio to its original state in the - // destructor. - // - // This is a Ptr instead of a ScopedPtr because it's lazily initialized - // (and ScopedPtr doesn't support re-assignment). - Ptr originally_enabled_; + // originally enabled, false if originally disabled. + // We restore the radio to its original state in the destructor. + + AtomicBoolean originally_enabled_{false}; + // false if we never modified the radio state, true otherwise. + AtomicBoolean ever_saved_state_{false}; }; } // namespace connections } // namespace nearby } // namespace location -#include "core/internal/mediums/bluetooth_radio.cc" - #endif // CORE_INTERNAL_MEDIUMS_BLUETOOTH_RADIO_H_ diff --git a/cpp/core_v2/internal/mediums/bluetooth_radio_test.cc b/cpp/core/internal/mediums/bluetooth_radio_test.cc similarity index 94% rename from cpp/core_v2/internal/mediums/bluetooth_radio_test.cc rename to cpp/core/internal/mediums/bluetooth_radio_test.cc index f02d19de..8f8e3a93 100644 --- a/cpp/core_v2/internal/mediums/bluetooth_radio_test.cc +++ b/cpp/core/internal/mediums/bluetooth_radio_test.cc @@ -1,4 +1,4 @@ -#include "core_v2/internal/mediums/bluetooth_radio.h" +#include "core/internal/mediums/bluetooth_radio.h" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/cpp/core/internal/mediums/discovered_peripheral_callback.h b/cpp/core/internal/mediums/discovered_peripheral_callback.h deleted file mode 100644 index 1e3fe35f..00000000 --- a/cpp/core/internal/mediums/discovered_peripheral_callback.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef CORE_INTERNAL_MEDIUMS_DISCOVERED_PERIPHERAL_CALLBACK_H_ -#define CORE_INTERNAL_MEDIUMS_DISCOVERED_PERIPHERAL_CALLBACK_H_ - -#include "core/internal/mediums/ble_peripheral.h" -#include "platform/byte_array.h" -#include "platform/port/string.h" -#include "platform/ptr.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -/** Callback that is invoked when a {@link BLEPeripheral} is discovered. */ -class DiscoveredPeripheralCallback { - public: - virtual ~DiscoveredPeripheralCallback() {} - - virtual void onPeripheralDiscovered(Ptr ble_peripheral, - const string& service_id, - ConstPtr advertisement, - bool is_fast_advertisement) = 0; - virtual void onPeripheralLost(Ptr ble_peripheral, - const string& service_id); -}; - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_INTERNAL_MEDIUMS_DISCOVERED_PERIPHERAL_CALLBACK_H_ diff --git a/cpp/core/internal/mediums/discovered_peripheral_tracker.cc b/cpp/core/internal/mediums/discovered_peripheral_tracker.cc deleted file mode 100644 index 276ec2cf..00000000 --- a/cpp/core/internal/mediums/discovered_peripheral_tracker.cc +++ /dev/null @@ -1,744 +0,0 @@ -#include "core/internal/mediums/discovered_peripheral_tracker.h" - -#include "core/internal/mediums/ble_packet.h" -#include "core/internal/mediums/bloom_filter.h" -#include "core/internal/mediums/utils.h" -#include "platform/synchronized.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -namespace dpt { - -template -void eraseOwnedPtrFromMap(std::map& m, const K& k) { - typename std::map::iterator it = m.find(k); - if (it != m.end()) { - it->second.destroy(); - m.erase(it); - } -} - -template -void eraseAllOwnedPtrsFromMap(std::map>& m) { - for (typename std::map>::iterator it = m.begin(); it != m.end(); - ++it) { - it->second.destroy(); - } - m.clear(); -} - -template -V removeOwnedPtrFromMap(std::map& m, const K& k) { - V removed_ptr; - typename std::map::iterator it = m.find(k); - if (it != m.end()) { - removed_ptr = it->second; - m.erase(it); - } - return removed_ptr; -} - -} // namespace dpt - -// The maximum number of advertisement slots to assume if we don't know the -// exact number. -template -const std::int32_t DiscoveredPeripheralTracker::kMaxSlots = 10; - -// Amount of time to wait before attempting a connection. This is needed to -// prevent the GATT server from operation overload if we just came from a GATT -// discovery. -template -const std::int64_t - DiscoveredPeripheralTracker::kMinConnectionDelayMillis = - 5 * 1000; // 5 seconds - -template -const char* DiscoveredPeripheralTracker::kCopresenceServiceUuid = - "0000FEF3-0000-1000-8000-00805F9B34FB"; - -template -DiscoveredPeripheralTracker::DiscoveredPeripheralTracker() - : lock_(Platform::createLock()), - thread_utils_(Platform::createThreadUtils()), - system_clock_(Platform::createSystemClock()), - hash_utils_(Platform::createHashUtils()), - discovered_peripheral_callbacks_(), - lost_entity_trackers_(), - fast_advertisement_service_uuids_(), - advertisement_read_results_(), - gatt_advertisements_(), - advertisement_service_ids_(), - advertisement_headers_(), - mac_addresses_() {} - -template -DiscoveredPeripheralTracker::~DiscoveredPeripheralTracker() { - Synchronized s(lock_.get()); - - mac_addresses_.clear(); - advertisement_headers_.clear(); - advertisement_service_ids_.clear(); - // gatt_advertisements_ maps a string to a Ptr to a set of ConstPtrs. We do - // not go and iterate through every set because those values are RefCounted. - dpt::eraseAllOwnedPtrsFromMap(gatt_advertisements_); - dpt::eraseAllOwnedPtrsFromMap(advertisement_read_results_); - fast_advertisement_service_uuids_.clear(); - dpt::eraseAllOwnedPtrsFromMap(lost_entity_trackers_); - dpt::eraseAllOwnedPtrsFromMap(discovered_peripheral_callbacks_); -} - -// Starts tracking discoveries for a particular service ID. -template -void DiscoveredPeripheralTracker::startTracking( - const string& service_id, - Ptr discovered_peripheral_callback, - const string& fast_advertisement_service_uuid) { - Synchronized s(lock_.get()); - - dpt::eraseOwnedPtrFromMap(discovered_peripheral_callbacks_, service_id); - discovered_peripheral_callbacks_.insert( - std::make_pair(service_id, discovered_peripheral_callback)); - - // We create a new LostEntityTracker because any pre-existing ones only - // contain stale advertisements. LostEntityTracker also doesn't provide a - // reset method, so creating a new one is the right way to go. - dpt::eraseOwnedPtrFromMap(lost_entity_trackers_, service_id); - lost_entity_trackers_.insert(std::make_pair( - service_id, - MakePtr(new LostEntityTracker()))); - - if (!fast_advertisement_service_uuid.empty()) { - fast_advertisement_service_uuids_.erase(service_id); - fast_advertisement_service_uuids_.insert( - std::make_pair(service_id, fast_advertisement_service_uuid)); - } - - // Clear all of the GATT read results. With this cleared, we will now attempt - // to reconnect to every peripheral we see, giving us a chance to search for - // the new service we're now tracking. - // See the documentation of advertisementReadResults for more information. - dpt::eraseAllOwnedPtrsFromMap(advertisement_read_results_); - - // Remove stale data from any previous sessions. - clearDataForServiceId(service_id); -} - -// Stops tracking discoveries for a particular service ID. -template -void DiscoveredPeripheralTracker::stopTracking( - const string& service_id) { - Synchronized s(lock_.get()); - - fast_advertisement_service_uuids_.erase(service_id); - dpt::eraseOwnedPtrFromMap(lost_entity_trackers_, service_id); - dpt::eraseOwnedPtrFromMap(discovered_peripheral_callbacks_, service_id); -} - -// Processes a found BLE advertisement. -template -void DiscoveredPeripheralTracker::processFoundBleAdvertisement( - Ptr ble_peripheral, - ConstPtr advertisement_data, - Ptr gatt_advertisement_fetcher) { - Synchronized s(lock_.get()); - - // Avoid leaks. - ScopedPtr> scoped_advertisement_data( - advertisement_data); - ScopedPtr> scoped_gatt_advertisement_fetcher( - gatt_advertisement_fetcher); - - if (getTrackedServiceIds().empty()) { - // TODO(ahlee) logger.atVerbose().log("Ignoring BLE advertisement header - // because we are not tracking any service IDs."); - return; - } - - if (ble_peripheral.isNull() || scoped_advertisement_data.isNull()) { - // TODO(ahlee) logger.atVerbose().log("Ignoring BLE advertisement header - // because the given BleSighting is null or incomplete."); - return; - } - - handleFastAdvertisement(ble_peripheral, scoped_advertisement_data.get()); - handleAdvertisementHeader(ble_peripheral, scoped_advertisement_data.get(), - scoped_gatt_advertisement_fetcher.get()); -} - -// Processes the set of lost GATT advertisements and notifies the client of any -// lost peripherals. -template -void DiscoveredPeripheralTracker::processLostGattAdvertisements() { - Synchronized s(lock_.get()); - - std::set tracked_service_ids = getTrackedServiceIds(); - for (typename std::set::iterator tsi_it = tracked_service_ids.begin(); - tsi_it != tracked_service_ids.end(); ++tsi_it) { - BLEAdvertisementSet lost_gatt_advertisements = - lost_entity_trackers_.find(*tsi_it)->second->computeLostEntities(); - - // Clear the map state for each lost GATT advertisement and report it to the - // client. - for (BLEAdvertisementSet::iterator lga_it = - lost_gatt_advertisements.begin(); - lga_it != lost_gatt_advertisements.end(); ++lga_it) { - clearGattAdvertisement(*lga_it); - discovered_peripheral_callbacks_.find(*tsi_it)->second->onPeripheralLost( - generateBlePeripheral(*lga_it), *tsi_it); - } - } -} - -template -Ptr DiscoveredPeripheralTracker::generateBlePeripheral( - ConstPtr gatt_advertisement) { - // TODO(ahlee): Reminder to port over deviceToken change. - return MakePtr(new BLEPeripheral(BLEAdvertisement::toBytes( - gatt_advertisement->getVersion(), gatt_advertisement->getSocketVersion(), - gatt_advertisement->getServiceIdHash(), gatt_advertisement->getData()))); -} - -template -std::set DiscoveredPeripheralTracker::getTrackedServiceIds() { - std::set tracked_service_ids; - for (DiscoveredPeripheralCallbackMap::iterator dpc_it = - discovered_peripheral_callbacks_.begin(); - dpc_it != discovered_peripheral_callbacks_.end(); ++dpc_it) { - tracked_service_ids.insert(dpc_it->first); - } - return tracked_service_ids; -} - -// Note: There is no C++ equivalent for getTrackedGattAdvertisements() because -// we make a copy of the subset of the keys in directly in -// clearDataForServiceId(). - -template -void DiscoveredPeripheralTracker::clearDataForServiceId( - const string& service_id) { - BLEAdvertisementSet gatt_advertisements_to_clear; - for (AdvertisementServiceIdMap::iterator it = - advertisement_service_ids_.begin(); - it != advertisement_service_ids_.end(); ++it) { - if (it->second != service_id) { - continue; - } - gatt_advertisements_to_clear.insert(it->first); - } - - for (BLEAdvertisementSet::iterator it = gatt_advertisements_to_clear.begin(); - it != gatt_advertisements_to_clear.end(); ++it) { - clearGattAdvertisement(*it); - } -} - -// Clears out all data related to the provided GATT advertisement. This -// includes: -// 1. Removing the GATT advertisement from GATT advertisement keyed maps. This -// includes advertisementServiceIds, AdvertisementHeaders, and -// macAddresses. -// 2. Removing the corresponding advertisement header from -// advertisementReadResults. -// 3. Removing the corresponding advertisement header from gattAdvertisements, -// only if there are no remaining GATT advertisements related to that -// header. -template -void DiscoveredPeripheralTracker::clearGattAdvertisement( - ConstPtr gatt_advertisement) { - // BLEAdvertisement is RefCounted, so it does not need to be scoped. - advertisement_service_ids_.erase(gatt_advertisement); - mac_addresses_.erase(gatt_advertisement); - - ConstPtr advertisement_header = - dpt::removeOwnedPtrFromMap(advertisement_headers_, gatt_advertisement); - typename GattAdvertisementMap::iterator ga_it = - gatt_advertisements_.find(advertisement_header); - if (ga_it != gatt_advertisements_.end()) { - // Remove the GATT advertisement from the advertisement header it's - // associated with. - Ptr header_gatt_advertisements = ga_it->second; - header_gatt_advertisements->erase(gatt_advertisement); - - // Unconditionally remove the header from advertisementReadResults so we - // can attempt to reread the GATT advertisement if they return. - dpt::eraseOwnedPtrFromMap(advertisement_read_results_, - advertisement_header); - - // If there are no more tracked GATT advertisements under this header, go - // ahead and remove it from gattAdvertisements. - if (header_gatt_advertisements->empty()) { - dpt::eraseOwnedPtrFromMap(gatt_advertisements_, advertisement_header); - } - } -} - -template -void DiscoveredPeripheralTracker::handleFastAdvertisement( - Ptr ble_peripheral, - ConstPtr advertisement_data) { - // Extract the fast advertisement bytes, if any. - ScopedPtr> fast_advertisement_bytes( - extractFastAdvertisementBytes(advertisement_data)); - if (fast_advertisement_bytes.isNull()) { - return; - } - - // Create a header tied to this fast advertisement. This helps us track the - // advertisement when reporting it as lost or connecting. - /* RefCounted */ ConstPtr fast_advertisement_header = - createFastAdvertisementHeader(fast_advertisement_bytes.get()); - - // Process the fast advertisement like we would a GATT advertisement and - // insert a placeholder AdvertisementReadResult. - dpt::eraseOwnedPtrFromMap(advertisement_read_results_, - fast_advertisement_header); - advertisement_read_results_.insert( - std::make_pair(fast_advertisement_header, - MakePtr(new AdvertisementReadResult()))); - - std::set> fast_advertisement_bytes_set; - fast_advertisement_bytes_set.insert(fast_advertisement_bytes.get()); - handleRawGattAdvertisements(fast_advertisement_header, - fast_advertisement_bytes_set, - /* are_fast_advertisements= */ true); - updateCommonStateForFoundBleAdvertisement(fast_advertisement_header, - ble_peripheral->getId()); -} - -template -void DiscoveredPeripheralTracker::handleAdvertisementHeader( - Ptr ble_peripheral, - ConstPtr advertisement_data, - Ptr gatt_advertisement_fetcher) { - // Attempt to parse the advertisement header. - /* RefCounted */ ConstPtr advertisement_header = - BLEAdvertisementHeader::fromString( - extractAdvertisementHeaderBytes(ble_peripheral, advertisement_data)); - if (advertisement_header.isNull()) { - // TODO(ahlee) logger.atVerbose().log("Failed to deserialize BLE - // advertisement header %s. Ignoring.", - // bytesToString(advertisementHeaderBytes)); - return; - } - - // Check if the advertisement header contains a service ID we're tracking. - if (!isInterestingAdvertisementHeader(advertisement_header)) { - // TODO(ahlee) logger.atVerbose().log("Ignoring BLE advertisement header %s - // because it does not contain any service IDs we're interested in.", - // advertisementHeader); - return; - } - - // Determine whether or not we need to read a fresh GATT advertisement. - if (shouldReadFromAdvertisementGattServer(advertisement_header)) { - // Determine whether or not we need to read a fresh GATT advertisement. - std::set> raw_gatt_advertisements = - fetchRawGattAdvertisements(ble_peripheral, advertisement_header, - gatt_advertisement_fetcher); - if (!raw_gatt_advertisements.empty()) { - handleRawGattAdvertisements(advertisement_header, raw_gatt_advertisements, - /* are_fast_advertisements= */ false); - } - } - - // Regardless of whether or not we read a new GATT advertisement, the maps - // should now be up-to-date. With this information, do some general - // housekeeping. - updateCommonStateForFoundBleAdvertisement( - advertisement_header, /* mac_address= */ ble_peripheral->getId()); -} - -template -string DiscoveredPeripheralTracker::extractAdvertisementHeaderBytes( - Ptr ble_peripheral, - ConstPtr advertisement_data) { - ConstPtr service_data; - std::map>::const_iterator sd_it = - advertisement_data->service_data.find(kCopresenceServiceUuid); - if (sd_it != advertisement_data->service_data.end()) { - service_data = sd_it->second; - } - const string& local_name = advertisement_data->local_name; // alias - - // A valid advertisement header lives in either the local name (iOS) or the - // service data (Android). - if (!service_data.isNull()) { - // TODO(ahlee) logger.atVerbose().log("Service data found on possible - // Android BLE peripheral at address %s", - // bleSighting.getDevice().getAddress()); - return string(service_data->getData(), service_data->size()); - } else if (!local_name.empty()) { - // TODO(ahlee) logger.atVerbose().log("Local name found on possible iOS BLE - // peripheral at address %s", bleSighting.getDevice().getAddress()); - return local_name; - } else { - // iOS peripherals have a bug where the local name sometimes doesn't appear. - // In that case, we should still take a look at the advertisement in case - // there's something valuable on the peripheral's GATT server. - - // TODO(ahlee) logger.atVerbose().log("BLE advertisement found with no - // service data or local name from BLE peripheral at address %s (could be a - // buggy iOS peripheral with a missing local name).", - // bleSighting.getDevice().getAddress()); - - // Create a phony BloomFilter that always contains the service ID we're - // looking for. - return createDummyAdvertisementHeaderBytes(ble_peripheral); - } -} - -template -ConstPtr -DiscoveredPeripheralTracker::extractFastAdvertisementBytes( - ConstPtr advertisement_data) { - ConstPtr fast_advertisement_bytes; - // Iterate through all tracked service IDs to see if any of their fast - // advertisements are contained within this BLE advertisement. - std::set tracked_service_ids = getTrackedServiceIds(); - for (typename std::set::iterator tsi_it = tracked_service_ids.begin(); - tsi_it != tracked_service_ids.end(); ++tsi_it) { - // First, check if a service UUID is tied to this service ID. - typename FastAdvertisementServiceUUIDMap::iterator fasu_it = - fast_advertisement_service_uuids_.find(*tsi_it); - if (fasu_it != fast_advertisement_service_uuids_.end()) { - const string& fast_advertisement_service_uuid = fasu_it->second; // alias - - // Then, check if there's service data for this fast advertisement - // service UUID. If so, we can short-circuit since all BLE - // advertisements can contain at most ONE fast advertisement. - typename std::map>::const_iterator sd_it = - advertisement_data->service_data.find( - fast_advertisement_service_uuid); - if (sd_it != advertisement_data->service_data.end()) { - // TODO(b/117432693): Remove this copy once Ptr is fully RefCounted. - fast_advertisement_bytes = MakeConstPtr( - new ByteArray(sd_it->second->getData(), sd_it->second->size())); - break; - } - } - } - return fast_advertisement_bytes; -} - -// Creates an advertisement header that's purely a hash of the fast -// advertisement, since they come with no header. -template -/* RefCounted */ ConstPtr -DiscoveredPeripheralTracker::createFastAdvertisementHeader( - ConstPtr fast_advertisement_bytes) { - // Our end goal is to have a fully zeroed-out byte array of the correct length - // representing an empty bloom filter. - // TODO(b/149938110): remove ScopedPtr. - ScopedPtr> bloom_filter_bytes{ConstPtr{ - new ByteArray{BLEAdvertisementHeader::kServiceIdBloomFilterLength}}}; - - ScopedPtr> advertisement_hash( - generateAdvertisementHash(fast_advertisement_bytes)); - return MakeRefCountedConstPtr(new BLEAdvertisementHeader( - BLEAdvertisementHeader::Version::V2, /* num_slots= */ 1, - bloom_filter_bytes.get(), advertisement_hash.get())); -} - -// Creates a dummy advertisement header that possibly contains all tracked -// service IDs. -template -string -DiscoveredPeripheralTracker::createDummyAdvertisementHeaderBytes( - Ptr ble_peripheral) { - // Put the service ID along with the dummy service ID into our bloom filter - // Note: BloomFilter length should always match - // BLEAdvertisementHeader::kServiceIdBloomFilterLength - ScopedPtr>> bloom_filter(new BloomFilter<10>()); - - std::set tracked_service_ids = getTrackedServiceIds(); - for (typename std::set::iterator tsi_it = tracked_service_ids.begin(); - tsi_it != tracked_service_ids.end(); ++tsi_it) { - bloom_filter->add(*tsi_it); - } - - const string& ble_peripheral_id = ble_peripheral->getId(); // alias - ScopedPtr> ble_peripheral_id_bytes(MakeConstPtr( - new ByteArray(ble_peripheral_id.data(), ble_peripheral_id.size()))); - ScopedPtr> advertisement_hash( - generateAdvertisementHash(ble_peripheral_id_bytes.get())); - return BLEAdvertisementHeader::asString(BLEAdvertisementHeader::Version::V2, - kMaxSlots, bloom_filter->asBytes(), - advertisement_hash.get()); -} - -template -bool DiscoveredPeripheralTracker::isInterestingAdvertisementHeader( - /* RefCounted */ ConstPtr advertisement_header) { - ScopedPtr>> bloom_filter( - new BloomFilter<10>(advertisement_header->getServiceIdBloomFilter())); - std::set tracked_service_ids = getTrackedServiceIds(); - for (typename std::set::iterator tsi_it = tracked_service_ids.begin(); - tsi_it != tracked_service_ids.end(); ++tsi_it) { - if (bloom_filter->possiblyContains(*tsi_it)) { - return true; - } - } - return false; -} - -template -bool DiscoveredPeripheralTracker:: - shouldReadFromAdvertisementGattServer( - /* RefCounted */ ConstPtr - advertisement_header) { - // Check if we have never seen this header. New headers should always be read. - typename AdvertisementReadResultMap::iterator arr_it = - advertisement_read_results_.find(advertisement_header); - if (arr_it == advertisement_read_results_.end()) { - // TODO(ahlee) logger.atDebug().log("Received advertisement header %s, but - // we have never seen it before. Will try reading its GATT advertisement.", - // advertisementHeader); - return true; - } - - // Extract the last read result for this particular header. - Ptr> advertisement_read_result = - arr_it->second; // alias - - // Now evaluate if we should retry reading. - switch (advertisement_read_result->evaluateRetryStatus()) { - case AdvertisementReadResult::RetryStatus::RETRY: - // TODO(ahlee) logger.atDebug().log("Received advertisement header %s. - // Will retry reading its GATT advertisement.", advertisementHeader); - return true; - case AdvertisementReadResult::RetryStatus::PREVIOUSLY_SUCCEEDED: - // TODO(ahlee) logger.atVerbose().log("Received advertisement header %s, - // but we have already read its GATT advertisement.", - // advertisementHeader); - return false; - case AdvertisementReadResult::RetryStatus::TOO_SOON: - // TODO(ahlee) logger.atDebug().log("Received advertisement header %s, but - // we have recently failed to read its GATT advertisement.", - // advertisementHeader); - return false; - case AdvertisementReadResult::RetryStatus::UNKNOWN: - // Fall through. - break; - } - - // TODO(ahlee) logger.atDebug().log("Received advertisement header %s, but we - // do not know whether or not to retry reading its GATT advertisement. Will - // retry to be safe.", advertisementHeader); - return true; -} - -template -std::set> -DiscoveredPeripheralTracker::fetchRawGattAdvertisements( - Ptr ble_peripheral, - /* RefCounted */ ConstPtr advertisement_header, - Ptr gatt_advertisement_fetcher) { - Ptr> old_advertisement_read_result; - typename AdvertisementReadResultMap::iterator arr_it = - advertisement_read_results_.find(advertisement_header); - if (arr_it != advertisement_read_results_.end()) { - old_advertisement_read_result = arr_it->second; // alias - } - - /* RefCounted */ Ptr> - advertisement_read_result = - gatt_advertisement_fetcher->fetchGattAdvertisements( - ble_peripheral, advertisement_header->getNumSlots(), - old_advertisement_read_result); - - dpt::eraseOwnedPtrFromMap(advertisement_read_results_, advertisement_header); - arr_it = advertisement_read_results_ - .insert(std::make_pair(advertisement_header, - advertisement_read_result)) - .first; - - return arr_it->second->getAdvertisements(); -} - -template -void DiscoveredPeripheralTracker::handleRawGattAdvertisements( - /* RefCounted */ ConstPtr advertisement_header, - const std::set>& raw_gatt_advertisements, - bool are_fast_advertisements) { - typedef std::map> BLEAdvertisementMap; - // Parse the raw GATT advertisements. The output of this method is a mapping - // of service ID -> GATT advertisement. - BLEAdvertisementMap parsed_gatt_advertisements = - parseRawGattAdvertisements(raw_gatt_advertisements); - ScopedPtr> parsed_gatt_advertisement_values( - new BLEAdvertisementSet()); - - // Update state for each GATT advertisement. - for (BLEAdvertisementMap::iterator pga_it = - parsed_gatt_advertisements.begin(); - pga_it != parsed_gatt_advertisements.end(); ++pga_it) { - const string& service_id = pga_it->first; // alias - ConstPtr gatt_advertisement = pga_it->second; // alias - parsed_gatt_advertisement_values->insert(gatt_advertisement); - - // TODO(ahlee): Update the java code to create old_advertisement_header - // within the if/else block. - AdvertisementHeaderMap::iterator ah_it = - advertisement_headers_.find(gatt_advertisement); - if (ah_it == advertisement_headers_.end()) { - discovered_peripheral_callbacks_.find(service_id) - ->second->onPeripheralDiscovered( - generateBlePeripheral(gatt_advertisement), service_id, - gatt_advertisement->getData(), are_fast_advertisements); - } else { - ConstPtr old_advertisement_header = - ah_it->second; // alias - dpt::eraseOwnedPtrFromMap(advertisement_read_results_, - old_advertisement_header); - dpt::eraseOwnedPtrFromMap(gatt_advertisements_, old_advertisement_header); - } - - dpt::eraseOwnedPtrFromMap(advertisement_headers_, gatt_advertisement); - advertisement_headers_.insert( - std::make_pair(gatt_advertisement, advertisement_header)); - - advertisement_service_ids_.erase(gatt_advertisement); - advertisement_service_ids_.insert( - std::make_pair(gatt_advertisement, service_id)); - } - - // Insert the list of read GATT advertisements for this advertisement header. - dpt::eraseOwnedPtrFromMap(gatt_advertisements_, advertisement_header); - gatt_advertisements_.insert(std::make_pair( - advertisement_header, parsed_gatt_advertisement_values.release())); -} - -// Returns a map of service IDs to GATT advertisements who belong to a tracked -// service ID. -template -std::map> -DiscoveredPeripheralTracker::parseRawGattAdvertisements( - const std::set>& raw_gatt_advertisements) { - std::set tracked_service_ids = getTrackedServiceIds(); - typedef std::map> BLEAdvertisementMap; - BLEAdvertisementMap parsed_gatt_advertisements; - for (std::set>::iterator rga_it = - raw_gatt_advertisements.begin(); - rga_it != raw_gatt_advertisements.end(); ++rga_it) { - /* RefCounted */ ConstPtr gatt_advertisement = - BLEAdvertisement::fromBytes(*rga_it); - if (gatt_advertisement.isNull()) { - // logger.atDebug().log("Unable to parse raw GATT advertisement %s", - // *rga_it); - continue; - } - - // Make sure the advertisement belongs to a service ID we're tracking. - for (typename std::set::iterator tsi_it = - tracked_service_ids.begin(); - tsi_it != tracked_service_ids.end(); ++tsi_it) { - // If we already found a higher version advertisement for this service ID, - // there's no point in comparing this advertisement against it. - BLEAdvertisementMap::iterator pga_it = - parsed_gatt_advertisements.find(*tsi_it); - if (pga_it != parsed_gatt_advertisements.end()) { - if (pga_it->second->getVersion() > gatt_advertisement->getVersion()) { - continue; - } - } - - // Map the service ID to the advertisement if the service ID hashes match. - ScopedPtr> service_id_hash( - generateServiceIdHash(gatt_advertisement->getVersion(), *tsi_it)); - if (*service_id_hash == *(gatt_advertisement->getServiceIdHash())) { - // logger.atDebug().log("Matched service ID %s to GATT advertisement - // %s.", serviceId, gattAdvertisement); - parsed_gatt_advertisements.insert( - std::make_pair(*tsi_it, gatt_advertisement)); - break; - } - } - } - - return parsed_gatt_advertisements; -} - -template -void DiscoveredPeripheralTracker:: - updateCommonStateForFoundBleAdvertisement( - /* RefCounted */ ConstPtr advertisement_header, - const string& mac_address) { - typename GattAdvertisementMap::iterator ga_it = - gatt_advertisements_.find(advertisement_header); - if (ga_it == gatt_advertisements_.end()) { - // logger.atDebug().log("No GATT advertisements found for advertisement - // header %s.", advertisementHeader); - return; - } - - Ptr saved_gatt_advertisements = ga_it->second; // alias - for (BLEAdvertisementSet::iterator sga_it = - saved_gatt_advertisements->begin(); - sga_it != saved_gatt_advertisements->end(); ++sga_it) { - ConstPtr gatt_advertisement = *sga_it; // alias - - AdvertisementServiceIdMap::iterator asi_it = - advertisement_service_ids_.find(gatt_advertisement); - if (asi_it == advertisement_service_ids_.end()) { - continue; - } - const string& service_id = asi_it->second; // alias - - // Make sure the stored GATT advertisement is still being tracked. - std::set tracked_service_ids = getTrackedServiceIds(); - if (tracked_service_ids.find(service_id) == tracked_service_ids.end()) { - continue; - } - - // The iterator returned from find() is guaranteed to be valid because it's - // tied to discovered_peripheral_callbacks_, whose keyset is checked through - // getTrackedServiceIds() above. - lost_entity_trackers_.find(service_id) - ->second->recordFoundEntity(gatt_advertisement); - - // The iterator returned from find() is guaranteed to be valid because it's - // tied to advertisement_service_ids_ which is checked at the beginning of - // the for loop. - mac_addresses_.erase(gatt_advertisement); - mac_addresses_.insert(std::make_pair(gatt_advertisement, mac_address)); - } -} - -template -ConstPtr -DiscoveredPeripheralTracker::generateAdvertisementHash( - ConstPtr advertisement_bytes) { - return Utils::sha256Hash(hash_utils_.get(), advertisement_bytes, - BLEAdvertisementHeader::kAdvertisementHashLength); -} - -template -ConstPtr -DiscoveredPeripheralTracker::generateServiceIdHash( - BLEAdvertisement::Version::Value version, const string& service_id) { - ScopedPtr> service_id_bytes( - MakeConstPtr(new ByteArray(service_id.data(), service_id.size()))); - switch (version) { - case BLEAdvertisement::Version::V1: - return Utils::legacySha256HashOnlyForPrinting( - hash_utils_.get(), service_id_bytes.get(), - BLEPacket::kServiceIdHashLength); - case BLEAdvertisement::Version::V2: - // Fall through. - case BLEAdvertisement::Version::UNKNOWN: - // Fall through. - default: - // Use the latest known hashing scheme. - return Utils::sha256Hash(hash_utils_.get(), service_id_bytes.get(), - BLEPacket::kServiceIdHashLength); - } -} - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core/internal/mediums/discovered_peripheral_tracker.h b/cpp/core/internal/mediums/discovered_peripheral_tracker.h deleted file mode 100644 index 7c23a3d8..00000000 --- a/cpp/core/internal/mediums/discovered_peripheral_tracker.h +++ /dev/null @@ -1,218 +0,0 @@ -#ifndef CORE_INTERNAL_MEDIUMS_DISCOVERED_PERIPHERAL_TRACKER_H_ -#define CORE_INTERNAL_MEDIUMS_DISCOVERED_PERIPHERAL_TRACKER_H_ - -#include -#include -#include - -#include "core/internal/mediums/advertisement_read_result.h" -#include "core/internal/mediums/ble_advertisement.h" -#include "core/internal/mediums/ble_advertisement_header.h" -#include "core/internal/mediums/ble_peripheral.h" -#include "core/internal/mediums/discovered_peripheral_callback.h" -#include "core/internal/mediums/lost_entity_tracker.h" -#include "platform/api/ble_v2.h" -#include "platform/api/hash_utils.h" -#include "platform/api/lock.h" -#include "platform/api/system_clock.h" -#include "platform/api/thread_utils.h" -#include "platform/byte_array.h" -#include "platform/port/string.h" -#include "platform/ptr.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -// Manages all discovered peripheral logic for {@link BluetoothLowEnergy}. This -// includes tracking found peripherals, lost peripherals, and MAC addresses -// associated with those peripherals. -// -// See go/ble-on-lost for more information. It includes the algorithms used to -// compute found and lost peripherals. -template -class DiscoveredPeripheralTracker { - public: - DiscoveredPeripheralTracker(); - ~DiscoveredPeripheralTracker(); - - void startTracking( - const string& service_id, - Ptr discovered_peripheral_callback, - const string& fast_advertisement_service_uuid); - void stopTracking(const string& service_id); - - // GATT advertisement fetcher. - class GattAdvertisementFetcher { - public: - virtual ~GattAdvertisementFetcher() {} - - // Fetches relevant GATT advertisements for the peripheral found in {@link - // DiscoveredPeripheralTracker#processFoundBleAdvertisement(BleSighting, - // GattAdvertisementFetcher)}. - virtual Ptr> fetchGattAdvertisements( - Ptr ble_peripheral, std::int32_t num_slots, - Ptr> advertisement_read_result) = 0; - }; - void processFoundBleAdvertisement( - Ptr ble_peripheral, - ConstPtr advertisement_data, - Ptr gatt_advertisement_fetcher); - void processLostGattAdvertisements(); - - // TODO(ahlee): Add connecting logic. - - private: - static Ptr generateBlePeripheral( - ConstPtr gatt_advertisement); - - static const std::int32_t kMaxSlots; - static const std::int64_t kMinConnectionDelayMillis; - static const char* kCopresenceServiceUuid; - - std::set getTrackedServiceIds(); - void clearDataForServiceId(const string& service_id); - void clearGattAdvertisement(ConstPtr gatt_advertisement); - void handleFastAdvertisement( - Ptr ble_peripheral, - ConstPtr advertisement_data); - void handleAdvertisementHeader( - Ptr ble_peripheral, - ConstPtr advertisement_data, - Ptr gatt_advertisement_fetcher); - string extractAdvertisementHeaderBytes( - Ptr ble_peripheral, - ConstPtr advertisement_data); - ConstPtr extractFastAdvertisementBytes( - ConstPtr advertisement_data); - /*RefCounted */ ConstPtr - createFastAdvertisementHeader(ConstPtr fast_advertisement_bytes); - string createDummyAdvertisementHeaderBytes( - Ptr ble_peripheral); - bool isInterestingAdvertisementHeader( - /* RefCounted */ ConstPtr advertisement_header); - bool shouldReadFromAdvertisementGattServer( - /* RefCounted */ ConstPtr advertisement_header); - std::set> fetchRawGattAdvertisements( - Ptr ble_peripheral, - /* RefCounted */ ConstPtr advertisement_header, - Ptr gatt_advertisement_fetcher); - void handleRawGattAdvertisements( - /* RefCounted */ ConstPtr advertisement_header, - const std::set>& raw_gatt_advertisements, - bool are_fast_advertisements); - std::map> parseRawGattAdvertisements( - const std::set>& raw_gatt_advertisements); - void updateCommonStateForFoundBleAdvertisement( - /* RefCounted */ ConstPtr advertisement_header, - const string& mac_address); - - // TODO(ahlee): Add in connecting logic. - - // TODO(ahlee): Move these out to utils (also used by BLE V2). - ConstPtr generateAdvertisementHash( - ConstPtr advertisement_bytes); - ConstPtr generateServiceIdHash( - BLEAdvertisement::Version::Value version, const string& service_id); - - // ------------ GENERAL ------------ - ScopedPtr> lock_; - ScopedPtr> thread_utils_; - ScopedPtr> system_clock_; - ScopedPtr> hash_utils_; - - // ------------ SERVICE ID MAPS ------------ - // Entries in these maps all follow the same lifecycle. Entries are added in - // startTracking, and removed in stopTracking. - - // Maps service IDs to DiscoveredPeripheralCallbacks. Tracks what service IDs - // are currently active and gives us client callbacks to call. - typedef std::map> - DiscoveredPeripheralCallbackMap; - DiscoveredPeripheralCallbackMap discovered_peripheral_callbacks_; - - // Maps service IDs to LostEntityTrackers. Used to periodically compute lost - // GATT advertisements, grouped by service ID. - typedef std::map>> - LostEntityTrackerMap; - LostEntityTrackerMap lost_entity_trackers_; - - // Maps service IDs to BLE service UUIDs. Used to check for fast - // advertisements delivered through BLE advertisement service data, under the - // given UUID. - // UUIDs are represented as strings in this map because they are coming from - // AdvertisingOptions and our UUID class is an internal concept that we don't - // want to expose to clients. - typedef std::map FastAdvertisementServiceUUIDMap; - FastAdvertisementServiceUUIDMap fast_advertisement_service_uuids_; - - // ------------ ADVERTISEMENT HEADER MAPS ------------ - - // Maps advertisement headers to AdvertisementReadResults. Tells us when to - // retry reading a GATT advertisement. If no entry exists for a particular - // header, we should try reading a GATT advertisement. Entries are added - // whenever a GATT advertisement read is attempted, and removed when GATT - // advertisements are lost. Entries are also removed whenever - // gattAdvertisements removes its entry. - // - // The map is also cleared whenever startTracking is called, due to client - // changes. For example, say clients A and B start scanning and discover - // advertisements A and B (for both clients) on advertisement header 1. Then, - // A restarts scanning, causing us to clear stale advertisement A. However, - // since B was still scanning, we don't remove advertisement header 1 from the - // map. This causes us to never re-read advertisement A. - typedef std::map, - Ptr>> - AdvertisementReadResultMap; - AdvertisementReadResultMap advertisement_read_results_; - - // Maps advertisement headers to a set of GATT advertisements from a single - // peripheral. Used to retrieve GATT advertisements that we need to reprocess - // every time a header is seen. Entries are added when GATT advertisements are - // read, removed when all associated GATT advertisements are lost or become - // stale, and replaced when the advertisement header is updated for a single - // remote peripheral. - typedef std::set> - BLEAdvertisementSet; - typedef std::map, - Ptr> - GattAdvertisementMap; - GattAdvertisementMap gatt_advertisements_; - - // ------------ GATT ADVERTISEMENT MAPS ------------ - // Entries in these maps all follow the same lifecycle. Entries are added when - // GATT advertisements are read, and removed when GATT advertisements are lost - // or become stale. - - // Maps GATT advertisements to the service ID it's associated with. Tracks - // what GATT advertisements are currently active. Used to determine which - // LostEntityTracker to invoke when advertisements are rediscovered. - typedef std::map, string> - AdvertisementServiceIdMap; - AdvertisementServiceIdMap advertisement_service_ids_; - - // Maps GATT advertisements to advertisement headers. Used to efficiently find - // advertisement headers to delete when GATT advertisements are updated. This - // is a reverse map of gatt_advertisements_. - typedef std::map, - /* RefCounted */ ConstPtr> - AdvertisementHeaderMap; - AdvertisementHeaderMap advertisement_headers_; - - // Maps GATT advertisements to MAC addresses. Used when we need to make a - // socket connection based off of the GATT advertisement alone. Entries are - // modified every time a GATT advertisement's advertisement header is seen. - typedef std::map, string> - MacAddressMap; - MacAddressMap mac_addresses_; -}; - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location - -#include "core/internal/mediums/discovered_peripheral_tracker.cc" - -#endif // CORE_INTERNAL_MEDIUMS_DISCOVERED_PERIPHERAL_TRACKER_H_ diff --git a/cpp/core/internal/mediums/lost_entity_tracker.cc b/cpp/core/internal/mediums/lost_entity_tracker.cc deleted file mode 100644 index 0122cb57..00000000 --- a/cpp/core/internal/mediums/lost_entity_tracker.cc +++ /dev/null @@ -1,56 +0,0 @@ -#include "core/internal/mediums/lost_entity_tracker.h" - -#include "platform/synchronized.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -template -LostEntityTracker::LostEntityTracker() - : lock_(Platform::createLock()), - current_entities_(), - previously_found_entities_() {} - -template -LostEntityTracker::~LostEntityTracker() { - previously_found_entities_.clear(); - current_entities_.clear(); -} - -template -void LostEntityTracker::recordFoundEntity( - ConstPtr entity) { - Synchronized s(lock_.get()); - - current_entities_.insert(entity); -} - -template -typename LostEntityTracker::EntitySet -LostEntityTracker::computeLostEntities() { - Synchronized s(lock_.get()); - - // The set of lost entities is the previously found set MINUS the currently - // found set. - for (typename EntitySet::iterator it = current_entities_.begin(); - it != current_entities_.end(); ++it) { - previously_found_entities_.erase(*it); - } - EntitySet lost_entities(previously_found_entities_.begin(), - previously_found_entities_.end()); - - // Update our previous and current sets. - previously_found_entities_.clear(); - previously_found_entities_.insert(current_entities_.begin(), - current_entities_.end()); - current_entities_.clear(); - - return lost_entities; -} - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core/internal/mediums/lost_entity_tracker.h b/cpp/core/internal/mediums/lost_entity_tracker.h index ad4fb7ae..8a4cd32c 100644 --- a/cpp/core/internal/mediums/lost_entity_tracker.h +++ b/cpp/core/internal/mediums/lost_entity_tracker.h @@ -1,10 +1,9 @@ #ifndef CORE_INTERNAL_MEDIUMS_LOST_ENTITY_TRACKER_H_ #define CORE_INTERNAL_MEDIUMS_LOST_ENTITY_TRACKER_H_ -#include - -#include "platform/api/lock.h" -#include "platform/ptr.h" +#include "platform/public/mutex.h" +#include "platform/public/mutex_lock.h" +#include "absl/container/flat_hash_set.h" namespace location { namespace nearby { @@ -14,36 +13,68 @@ namespace mediums { // Tracks "lost" entities based on a manual update/compute model. Used by // mediums that only report found devices. Lost entities are computed based off // of whether a specific entity was rediscovered since the last call to -// computeLostEntities. +// ComputeLostEntities. // // Note: Entity must overload the < and == operators. -template +template class LostEntityTracker { public: - typedef std::set > EntitySet; + using EntitySet = absl::flat_hash_set; LostEntityTracker(); ~LostEntityTracker(); // Records the given entity as being recently found, whether or not this is // our first time discovering the entity. - void recordFoundEntity(ConstPtr entity); + void RecordFoundEntity(const Entity& entity) ABSL_LOCKS_EXCLUDED(mutex_); // Computes and returns the set of entities considered lost since the last // time this method was called. - EntitySet computeLostEntities(); + EntitySet ComputeLostEntities() ABSL_LOCKS_EXCLUDED(mutex_); private: - ScopedPtr > lock_; - EntitySet current_entities_; - EntitySet previously_found_entities_; + Mutex mutex_; + EntitySet current_entities_ ABSL_GUARDED_BY(mutex_); + EntitySet previously_found_entities_ ABSL_GUARDED_BY(mutex_); }; +template +LostEntityTracker::LostEntityTracker() + : current_entities_{}, previously_found_entities_{} {} + +template +LostEntityTracker::~LostEntityTracker() { + previously_found_entities_.clear(); + current_entities_.clear(); +} + +template +void LostEntityTracker::RecordFoundEntity(const Entity& entity) { + MutexLock lock(&mutex_); + + current_entities_.insert(entity); +} + +template +typename LostEntityTracker::EntitySet +LostEntityTracker::ComputeLostEntities() { + MutexLock lock(&mutex_); + + // The set of lost entities is the previously found set MINUS the currently + // found set. + for (const auto& item : current_entities_) { + previously_found_entities_.erase(item); + } + auto lost_entities = std::move(previously_found_entities_); + previously_found_entities_ = std::move(current_entities_); + current_entities_ = {}; + + return lost_entities; +} + } // namespace mediums } // namespace connections } // namespace nearby } // namespace location -#include "core/internal/mediums/lost_entity_tracker.cc" - #endif // CORE_INTERNAL_MEDIUMS_LOST_ENTITY_TRACKER_H_ diff --git a/cpp/core/internal/mediums/lost_entity_tracker_test.cc b/cpp/core/internal/mediums/lost_entity_tracker_test.cc index bb4b2ef9..5c6e10c0 100644 --- a/cpp/core/internal/mediums/lost_entity_tracker_test.cc +++ b/cpp/core/internal/mediums/lost_entity_tracker_test.cc @@ -1,6 +1,5 @@ #include "core/internal/mediums/lost_entity_tracker.h" -#include "platform/api/platform.h" #include "gtest/gtest.h" namespace location { @@ -9,111 +8,112 @@ namespace connections { namespace mediums { namespace { -using TestPlatform = platform::ImplementationPlatform; - struct TestEntity { int id; - explicit TestEntity(int givenId) : id(givenId) {} + template + friend H AbslHashValue(H h, const TestEntity& test_entity) { + return H::combine(std::move(h), test_entity.id); + } - bool operator<(const TestEntity &other) const { return id < other.id; } + bool operator==(const TestEntity& other) const { return id == other.id; } + bool operator<(const TestEntity& other) const { return id < other.id; } }; -TEST(LostEntityTracker, NoEntitiesLost) { - LostEntityTracker lost_entity_tracker; - ScopedPtr > entity_1(MakeConstPtr(new TestEntity(1))); - ScopedPtr > entity_2(MakeConstPtr(new TestEntity(2))); - ScopedPtr > entity_3(MakeConstPtr(new TestEntity(3))); +TEST(LostEntityTrackerTest, NoEntitiesLost) { + LostEntityTracker lost_entity_tracker; + TestEntity entity_1{1}; + TestEntity entity_2{2}; + TestEntity entity_3{3}; // Discover some entities. - lost_entity_tracker.recordFoundEntity(entity_1.get()); - lost_entity_tracker.recordFoundEntity(entity_2.get()); - lost_entity_tracker.recordFoundEntity(entity_3.get()); + lost_entity_tracker.RecordFoundEntity(entity_1); + lost_entity_tracker.RecordFoundEntity(entity_2); + lost_entity_tracker.RecordFoundEntity(entity_3); // Make sure none are lost on the first round. - ASSERT_TRUE(lost_entity_tracker.computeLostEntities().empty()); + ASSERT_TRUE(lost_entity_tracker.ComputeLostEntities().empty()); // Rediscover the same entities. - lost_entity_tracker.recordFoundEntity(entity_1.get()); - lost_entity_tracker.recordFoundEntity(entity_2.get()); - lost_entity_tracker.recordFoundEntity(entity_3.get()); + lost_entity_tracker.RecordFoundEntity(entity_1); + lost_entity_tracker.RecordFoundEntity(entity_2); + lost_entity_tracker.RecordFoundEntity(entity_3); // Make sure we still didn't lose any entities. - ASSERT_TRUE(lost_entity_tracker.computeLostEntities().empty()); + EXPECT_TRUE(lost_entity_tracker.ComputeLostEntities().empty()); } -TEST(LostEntityTracker, AllEntitiesLost) { - LostEntityTracker lost_entity_tracker; - ScopedPtr > entity_1(MakeConstPtr(new TestEntity(1))); - ScopedPtr > entity_2(MakeConstPtr(new TestEntity(2))); - ScopedPtr > entity_3(MakeConstPtr(new TestEntity(3))); +TEST(LostEntityTrackerTest, AllEntitiesLost) { + LostEntityTracker lost_entity_tracker; + TestEntity entity_1{1}; + TestEntity entity_2{2}; + TestEntity entity_3{3}; // Discover some entities. - lost_entity_tracker.recordFoundEntity(entity_1.get()); - lost_entity_tracker.recordFoundEntity(entity_2.get()); - lost_entity_tracker.recordFoundEntity(entity_3.get()); + lost_entity_tracker.RecordFoundEntity(entity_1); + lost_entity_tracker.RecordFoundEntity(entity_2); + lost_entity_tracker.RecordFoundEntity(entity_3); // Make sure none are lost on the first round. - ASSERT_TRUE(lost_entity_tracker.computeLostEntities().empty()); + EXPECT_TRUE(lost_entity_tracker.ComputeLostEntities().empty()); // Go through a round without rediscovering any entities. - typename LostEntityTracker::EntitySet - lost_entities = lost_entity_tracker.computeLostEntities(); - ASSERT_TRUE(lost_entities.find(entity_1.get()) != lost_entities.end()); - ASSERT_TRUE(lost_entities.find(entity_2.get()) != lost_entities.end()); - ASSERT_TRUE(lost_entities.find(entity_3.get()) != lost_entities.end()); + typename LostEntityTracker::EntitySet lost_entities = + lost_entity_tracker.ComputeLostEntities(); + EXPECT_TRUE(lost_entities.find(entity_1) != lost_entities.end()); + EXPECT_TRUE(lost_entities.find(entity_2) != lost_entities.end()); + EXPECT_TRUE(lost_entities.find(entity_3) != lost_entities.end()); } -TEST(LostEntityTracker, SomeEntitiesLost) { - LostEntityTracker lost_entity_tracker; - ScopedPtr > entity_1(MakeConstPtr(new TestEntity(1))); - ScopedPtr > entity_2(MakeConstPtr(new TestEntity(2))); - ScopedPtr > entity_3(MakeConstPtr(new TestEntity(3))); +TEST(LostEntityTrackerTest, SomeEntitiesLost) { + LostEntityTracker lost_entity_tracker; + TestEntity entity_1{1}; + TestEntity entity_2{2}; + TestEntity entity_3{3}; // Discover some entities. - lost_entity_tracker.recordFoundEntity(entity_1.get()); - lost_entity_tracker.recordFoundEntity(entity_2.get()); + lost_entity_tracker.RecordFoundEntity(entity_1); + lost_entity_tracker.RecordFoundEntity(entity_2); // Make sure none are lost on the first round. - ASSERT_TRUE(lost_entity_tracker.computeLostEntities().empty()); + EXPECT_TRUE(lost_entity_tracker.ComputeLostEntities().empty()); // Go through the next round only rediscovering one of our entities and // discovering an additional entity as well. Then, verify that only one entity // was lost after the check. - lost_entity_tracker.recordFoundEntity(entity_1.get()); - lost_entity_tracker.recordFoundEntity(entity_3.get()); - typename LostEntityTracker::EntitySet - lost_entities = lost_entity_tracker.computeLostEntities(); - ASSERT_TRUE(lost_entities.find(entity_1.get()) == lost_entities.end()); - ASSERT_TRUE(lost_entities.find(entity_2.get()) != lost_entities.end()); - ASSERT_TRUE(lost_entities.find(entity_3.get()) == lost_entities.end()); + lost_entity_tracker.RecordFoundEntity(entity_1); + lost_entity_tracker.RecordFoundEntity(entity_3); + typename LostEntityTracker::EntitySet lost_entities = + lost_entity_tracker.ComputeLostEntities(); + EXPECT_TRUE(lost_entities.find(entity_1) == lost_entities.end()); + EXPECT_TRUE(lost_entities.find(entity_2) != lost_entities.end()); + EXPECT_TRUE(lost_entities.find(entity_3) == lost_entities.end()); } -TEST(LostEntityTracker, SameEntityMultipleCopies) { - LostEntityTracker lost_entity_tracker; - ScopedPtr > entity_1(MakeConstPtr(new TestEntity(1))); - ScopedPtr > entity_1_copy( - MakeConstPtr(new TestEntity(1))); +TEST(LostEntityTrackerTest, SameEntityMultipleCopies) { + LostEntityTracker lost_entity_tracker; + TestEntity entity_1{1}; + TestEntity entity_1_copy{1}; // Discover an entity. - lost_entity_tracker.recordFoundEntity(entity_1.get()); + lost_entity_tracker.RecordFoundEntity(entity_1); // Make sure none are lost on the first round. - ASSERT_TRUE(lost_entity_tracker.computeLostEntities().empty()); + EXPECT_TRUE(lost_entity_tracker.ComputeLostEntities().empty()); // Rediscover the same entity, but through a copy of it. - lost_entity_tracker.recordFoundEntity(entity_1_copy.get()); + lost_entity_tracker.RecordFoundEntity(entity_1_copy); // Make sure none are lost on the second round. - ASSERT_TRUE(lost_entity_tracker.computeLostEntities().empty()); + EXPECT_TRUE(lost_entity_tracker.ComputeLostEntities().empty()); // Go through a round without rediscovering any entities and verify that we // lost an entity equivalent to both copies of it. - typename LostEntityTracker::EntitySet - lost_entities = lost_entity_tracker.computeLostEntities(); - ASSERT_EQ(lost_entities.size(), 1); - ASSERT_TRUE(lost_entities.find(entity_1.get()) != lost_entities.end()); - ASSERT_TRUE(lost_entities.find(entity_1_copy.get()) != lost_entities.end()); + typename LostEntityTracker::EntitySet lost_entities = + lost_entity_tracker.ComputeLostEntities(); + EXPECT_EQ(lost_entities.size(), 1); + EXPECT_TRUE(lost_entities.find(entity_1) != lost_entities.end()); + EXPECT_TRUE(lost_entities.find(entity_1_copy) != lost_entities.end()); } } // namespace diff --git a/cpp/core/internal/mediums/mediums.cc b/cpp/core/internal/mediums/mediums.cc index 65d19764..ff85310b 100644 --- a/cpp/core/internal/mediums/mediums.cc +++ b/cpp/core/internal/mediums/mediums.cc @@ -4,44 +4,21 @@ namespace location { namespace nearby { namespace connections { -template -Mediums::Mediums() - : bluetooth_radio_(new BluetoothRadio()), - bluetooth_classic_( - new BluetoothClassic(bluetooth_radio_.get())), - ble_(new BLE(bluetooth_radio_.get())), - ble_v2_(new mediums::BLEV2(bluetooth_radio_.get())), - wifi_lan_(new mediums::WifiLan()) {} - -template -Mediums::~Mediums() { - // Nothing to do. +BluetoothRadio& Mediums::GetBluetoothRadio() { + return bluetooth_radio_; } -template -Ptr > Mediums::bluetoothRadio() const { - return bluetooth_radio_.get(); +BluetoothClassic& Mediums::GetBluetoothClassic() { + return bluetooth_classic_; } -template -Ptr > Mediums::bluetoothClassic() const { - return bluetooth_classic_.get(); +Ble& Mediums::GetBle() { return ble_; } + +WifiLan& Mediums::GetWifiLan() { + return wifi_lan_; } -template -Ptr > Mediums::ble() const { - return ble_.get(); -} - -template -Ptr > Mediums::bleV2() const { - return ble_v2_.get(); -} - -template -Ptr > Mediums::wifi_lan() const { - return wifi_lan_.get(); -} +mediums::WebRtc& Mediums::GetWebRtc() { return webrtc_; } } // namespace connections } // namespace nearby diff --git a/cpp/core/internal/mediums/mediums.h b/cpp/core/internal/mediums/mediums.h index fed971fa..5266dde1 100644 --- a/cpp/core/internal/mediums/mediums.h +++ b/cpp/core/internal/mediums/mediums.h @@ -2,34 +2,35 @@ #define CORE_INTERNAL_MEDIUMS_MEDIUMS_H_ #include "core/internal/mediums/ble.h" -#include "core/internal/mediums/ble_v2.h" #include "core/internal/mediums/bluetooth_classic.h" #include "core/internal/mediums/bluetooth_radio.h" +#include "core/internal/mediums/webrtc.h" #include "core/internal/mediums/wifi_lan.h" -#include "platform/ptr.h" namespace location { namespace nearby { namespace connections { // Facilitates convenient and reliable usage of various wireless mediums. -template class Mediums { public: - Mediums(); - // Reverts all the mediums to their original state. - ~Mediums(); + Mediums() = default; + ~Mediums() = default; // Returns a handle to the Bluetooth radio. - Ptr > bluetoothRadio() const; + BluetoothRadio& GetBluetoothRadio(); + // Returns a handle to the Bluetooth Classic medium. - Ptr > bluetoothClassic() const; - // Returns a handle to the Bluetooth Low Energy (BLE) medium. - Ptr > ble() const; - // Returns a handle to V2 of the Bluetooth Low Energy (BLE) medium. - Ptr > bleV2() const; + BluetoothClassic& GetBluetoothClassic(); + + // Returns a handle to the Ble medium. + Ble& GetBle(); + // Returns a handle to the Wifi-Lan medium. - Ptr > wifi_lan() const; + WifiLan& GetWifiLan(); + + // Returns a handle to the WebRtc medium. + mediums::WebRtc& GetWebRtc(); private: // The order of declaration is critical for both construction and @@ -40,17 +41,15 @@ class Mediums { // // 2) Destruction: The individual mediums should be shut down before the // corresponding radio. - ScopedPtr > > bluetooth_radio_; - ScopedPtr > > bluetooth_classic_; - ScopedPtr > > ble_; - ScopedPtr > > ble_v2_; - ScopedPtr > > wifi_lan_; + BluetoothRadio bluetooth_radio_; + BluetoothClassic bluetooth_classic_{bluetooth_radio_}; + Ble ble_{bluetooth_radio_}; + WifiLan wifi_lan_; + mediums::WebRtc webrtc_; }; } // namespace connections } // namespace nearby } // namespace location -#include "core/internal/mediums/mediums.cc" - #endif // CORE_INTERNAL_MEDIUMS_MEDIUMS_H_ diff --git a/cpp/core/internal/mediums/utils.cc b/cpp/core/internal/mediums/utils.cc index 72f08ef7..410f0495 100644 --- a/cpp/core/internal/mediums/utils.cc +++ b/cpp/core/internal/mediums/utils.cc @@ -1,63 +1,27 @@ #include "core/internal/mediums/utils.h" -#include -#include +#include +#include -#include "platform/exception.h" -#include "platform/prng.h" -#include "absl/strings/escaping.h" +#include "platform/base/prng.h" +#include "platform/public/crypto.h" namespace location { namespace nearby { namespace connections { -void Utils::closeSocket(Ptr socket, - const std::string& type, const std::string& name) { - if (!socket.isNull()) { - Exception::Value e = socket->close(); - if (Exception::NONE != e) { - if (Exception::IO == e) { - // TODO(reznor): log.atWarning().withCause(e).log("Failed to close - // %sSocket %s", type, name); - } - return; - } - // TODO(reznor): log.atVerbose().log("Closed %sSocket %s", type, name); - } +namespace { +constexpr absl::string_view kUpgradeServiceIdPostfix = "_UPGRADE"; } -ConstPtr Utils::sha256Hash(Ptr hash_utils, - ConstPtr source, - size_t length) { - if (source.isNull()) { - return ConstPtr(); - } - - ScopedPtr> full_hash( - hash_utils->sha256(std::string(source->getData(), source->size()))); - return MakeConstPtr(new ByteArray(full_hash->getData(), length)); -} - -ConstPtr Utils::legacySha256HashOnlyForPrinting( - Ptr hash_utils, ConstPtr source, size_t length) { - if (source.isNull()) { - return ConstPtr(); - } - - std::string formatted_hex_string = Utils::bytesToPrintableHexString(source); - ScopedPtr> formatted_hex_byte_array(MakeConstPtr( - new ByteArray(formatted_hex_string.data(), formatted_hex_string.size()))); - return Utils::sha256Hash(hash_utils, formatted_hex_byte_array.get(), length); -} - -ConstPtr Utils::generateRandomBytes(size_t length) { +ByteArray Utils::GenerateRandomBytes(size_t length) { Prng rng; std::string data; data.reserve(length); // Adds 4 random bytes per iteration. while (length > 0) { - std::uint32_t val = rng.nextUInt32(); + std::uint32_t val = rng.NextUint32(); for (int i = 0; i < 4; i++) { data += val & 0xFF; val >>= 8; @@ -67,27 +31,46 @@ ConstPtr Utils::generateRandomBytes(size_t length) { } } - return MakeConstPtr(new ByteArray(data)); + return ByteArray(data); } -std::string Utils::bytesToPrintableHexString(ConstPtr bytes) { - std::string hex_string( - absl::BytesToHexString(std::string(bytes->getData(), bytes->size()))); +ByteArray Utils::Sha256Hash(const ByteArray& source, size_t length) { + return Utils::Sha256Hash(std::string(source), length); +} - // Print out the byte array as a space separated listing of hex bytes. - std::ostringstream formatted_hex_string_stream; - formatted_hex_string_stream << "[ "; - for (int i = 0; i < hex_string.size(); i += 2) { - formatted_hex_string_stream << "0x"; - // This is safe because we have the guarantee that hex_string is of even - // length (because a hex encoding will always be double the size of its - // input). - formatted_hex_string_stream << hex_string[i] << hex_string[i + 1]; - formatted_hex_string_stream << " "; +ByteArray Utils::Sha256Hash(const std::string& source, size_t length) { + ByteArray full_hash(length); + full_hash.CopyAt(0, Crypto::Sha256(source)); + return full_hash; +} + +std::string Utils::WrapUpgradeServiceId(const std::string& service_id) { + if (service_id.empty()) { + return {}; } - formatted_hex_string_stream << "]"; + return service_id + std::string(kUpgradeServiceIdPostfix); +} - return formatted_hex_string_stream.str(); +std::string Utils::UnwrapUpgradeServiceId( + const std::string& upgrade_service_id) { + auto pos = upgrade_service_id.find(std::string(kUpgradeServiceIdPostfix)); + if (pos != std::string::npos) { + return std::string(upgrade_service_id, 0, pos); + } + return upgrade_service_id; +} + +LocationHint Utils::BuildLocationHint(const std::string& location) { + LocationHint location_hint; + if (!location.empty()) { + location_hint.set_location(location); + if (location.at(0) == '+') { + location_hint.set_format(LocationStandard::E164_CALLING); + } else { + location_hint.set_format(LocationStandard::ISO_3166_1_ALPHA_2); + } + } + return location_hint; } } // namespace connections diff --git a/cpp/core/internal/mediums/utils.h b/cpp/core/internal/mediums/utils.h index bb5e7704..b3e01a55 100644 --- a/cpp/core/internal/mediums/utils.h +++ b/cpp/core/internal/mediums/utils.h @@ -1,11 +1,11 @@ #ifndef CORE_INTERNAL_MEDIUMS_UTILS_H_ #define CORE_INTERNAL_MEDIUMS_UTILS_H_ -#include "platform/api/bluetooth_classic.h" -#include "platform/api/hash_utils.h" -#include "platform/byte_array.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include + +#include "proto/connections/offline_wire_formats.pb.h" +#include "proto/connections/offline_wire_formats.pb.h" +#include "platform/base/byte_array.h" namespace location { namespace nearby { @@ -13,18 +13,12 @@ namespace connections { class Utils { public: - static void closeSocket(Ptr socket, - const std::string& type, const std::string& name); - static ConstPtr sha256Hash(Ptr hash_utils, - ConstPtr source, - size_t length); - static ConstPtr legacySha256HashOnlyForPrinting( - Ptr hash_utils, ConstPtr source, size_t length); - - static ConstPtr generateRandomBytes(size_t length); - - private: - static std::string bytesToPrintableHexString(ConstPtr bytes); + static ByteArray GenerateRandomBytes(size_t length); + static ByteArray Sha256Hash(const ByteArray& source, size_t length); + static ByteArray Sha256Hash(const std::string& source, size_t length); + static std::string WrapUpgradeServiceId(const std::string& service_id); + static std::string UnwrapUpgradeServiceId(const std::string& service_id); + static LocationHint BuildLocationHint(const std::string& location); }; } // namespace connections diff --git a/cpp/core/internal/mediums/uuid.cc b/cpp/core/internal/mediums/uuid.cc index df6bed62..0208fd17 100644 --- a/cpp/core/internal/mediums/uuid.cc +++ b/cpp/core/internal/mediums/uuid.cc @@ -3,30 +3,33 @@ #include #include -#include "platform/api/hash_utils.h" -#include "platform/ptr.h" +#include "platform/public/crypto.h" namespace location { namespace nearby { namespace connections { +namespace { +std::ostream& write_hex(std::ostream& os, absl::string_view data) { + for (const auto b : data) { + os << std::setfill('0') + << std::setw(2) + << std::hex + << (static_cast(b) & 0x0ff); + } + return os; +} +} // namespace -template -UUID::UUID(const string& data) { +Uuid::Uuid(absl::string_view data) : data_(Crypto::Md5(data)) { // Based on the Java counterpart at // http://androidxref.com/8.0.0_r4/xref/libcore/ojluni/src/main/java/java/util/UUID.java#162. - ScopedPtr > scoped_hash_utils(Platform::createHashUtils()); - ScopedPtr > scoped_md5_bytes( - scoped_hash_utils->md5(data)); - data_.assign(scoped_md5_bytes->getData(), scoped_md5_bytes->size()); - data_[6] &= 0x0f; // Clear version. data_[6] |= 0x30; // Set to version 3. data_[8] &= 0x3f; // Clear variant. data_[8] |= 0x80; // Set to IETF variant. } -template -UUID::UUID(std::int64_t most_sig_bits, std::int64_t least_sig_bits) { +Uuid::Uuid(std::uint64_t most_sig_bits, std::uint64_t least_sig_bits) { // Base on the Java counterpart at // http://androidxref.com/8.0.0_r4/xref/libcore/ojluni/src/main/java/java/util/UUID.java#104. data_.reserve(sizeof(most_sig_bits) + sizeof(least_sig_bits)); @@ -50,47 +53,19 @@ UUID::UUID(std::int64_t most_sig_bits, std::int64_t least_sig_bits) { data_[15] = static_cast((least_sig_bits >> 0) & 0x0ff); } -template -UUID::~UUID() {} - -template -string UUID::str() { +Uuid::operator std::string() const { // Based on the Java counterpart at // http://androidxref.com/8.0.0_r4/xref/libcore/ojluni/src/main/java/java/util/UUID.java#375. - - // The masking with 0x0ff is essential because we're taking 8-bit bytes and - // casting them to integers (which, depending on the platform, are 16- or - // 32-bits wide); without that, we get a leading FF (16-bit) or FFFFFF - // (32-bit) when the MSB of the 8-bit byte is 1. - // - // And the cast to an integer is required because std::hex only takes effect - // on integral types (and no, uint8_t doesn't activate it). -#define BYTE_TO_HEX(b) \ - std::setfill('0') << std::setw(2) << std::hex \ - << (static_cast(b) & 0x0ff) - std::ostringstream md5_hex; - - md5_hex << BYTE_TO_HEX(data_[0]); - md5_hex << BYTE_TO_HEX(data_[1]); - md5_hex << BYTE_TO_HEX(data_[2]); - md5_hex << BYTE_TO_HEX(data_[3]); + write_hex(md5_hex, absl::string_view(&data_[0], 4)); md5_hex << "-"; - md5_hex << BYTE_TO_HEX(data_[4]); - md5_hex << BYTE_TO_HEX(data_[5]); + write_hex(md5_hex, absl::string_view(&data_[4], 2)); md5_hex << "-"; - md5_hex << BYTE_TO_HEX(data_[6]); - md5_hex << BYTE_TO_HEX(data_[7]); + write_hex(md5_hex, absl::string_view(&data_[6], 2)); md5_hex << "-"; - md5_hex << BYTE_TO_HEX(data_[8]); - md5_hex << BYTE_TO_HEX(data_[9]); + write_hex(md5_hex, absl::string_view(&data_[8], 2)); md5_hex << "-"; - md5_hex << BYTE_TO_HEX(data_[10]); - md5_hex << BYTE_TO_HEX(data_[11]); - md5_hex << BYTE_TO_HEX(data_[12]); - md5_hex << BYTE_TO_HEX(data_[13]); - md5_hex << BYTE_TO_HEX(data_[14]); - md5_hex << BYTE_TO_HEX(data_[15]); + write_hex(md5_hex, absl::string_view(&data_[10], 6)); return md5_hex.str(); } diff --git a/cpp/core/internal/mediums/uuid.h b/cpp/core/internal/mediums/uuid.h index 5a7a95e7..630ae518 100644 --- a/cpp/core/internal/mediums/uuid.h +++ b/cpp/core/internal/mediums/uuid.h @@ -2,8 +2,9 @@ #define CORE_INTERNAL_MEDIUMS_UUID_H_ #include +#include -#include "platform/port/string.h" +#include "absl/strings/string_view.h" namespace location { namespace nearby { @@ -14,17 +15,24 @@ namespace connections { // UUID. // // https://developer.android.com/reference/java/util/UUID.html -template -class UUID { +class Uuid final { public: - explicit UUID(const std::string& data); - UUID(std::int64_t most_sig_bits, std::int64_t least_sig_bits); - ~UUID(); + Uuid() : Uuid("uuid") {} + explicit Uuid(absl::string_view data); + Uuid(std::uint64_t most_sig_bits, std::uint64_t least_sig_bits); + Uuid(const Uuid&) = default; + Uuid& operator=(const Uuid&) = default; + Uuid(Uuid&&) = default; + Uuid& operator=(Uuid&&) = default; + ~Uuid() = default; // Returns the canonical textual representation // (https://en.wikipedia.org/wiki/Universally_unique_identifier#Format) of the // UUID. - std::string str(); + explicit operator std::string() const; + std::string data() const { + return data_; + } private: std::string data_; @@ -34,6 +42,4 @@ class UUID { } // namespace nearby } // namespace location -#include "core/internal/mediums/uuid.cc" - #endif // CORE_INTERNAL_MEDIUMS_UUID_H_ diff --git a/cpp/core_v2/internal/mediums/uuid_test.cc b/cpp/core/internal/mediums/uuid_test.cc similarity index 93% rename from cpp/core_v2/internal/mediums/uuid_test.cc rename to cpp/core/internal/mediums/uuid_test.cc index b2df4bb8..9d59fadc 100644 --- a/cpp/core_v2/internal/mediums/uuid_test.cc +++ b/cpp/core/internal/mediums/uuid_test.cc @@ -1,7 +1,7 @@ -#include "core_v2/internal/mediums/uuid.h" +#include "core/internal/mediums/uuid.h" -#include "platform_v2/public/crypto.h" -#include "platform_v2/public/logging.h" +#include "platform/public/crypto.h" +#include "platform/public/logging.h" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/cpp/core_v2/internal/mediums/webrtc.cc b/cpp/core/internal/mediums/webrtc.cc similarity index 92% rename from cpp/core_v2/internal/mediums/webrtc.cc rename to cpp/core/internal/mediums/webrtc.cc index ba498346..9c46feec 100644 --- a/cpp/core_v2/internal/mediums/webrtc.cc +++ b/cpp/core/internal/mediums/webrtc.cc @@ -1,16 +1,16 @@ -#include "core_v2/internal/mediums/webrtc.h" +#include "core/internal/mediums/webrtc.h" #include #include -#include "core_v2/internal/mediums/webrtc/session_description_wrapper.h" -#include "core_v2/internal/mediums/webrtc/signaling_frames.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/listeners.h" -#include "platform_v2/public/cancelable_alarm.h" -#include "platform_v2/public/future.h" -#include "platform_v2/public/logging.h" -#include "platform_v2/public/mutex_lock.h" +#include "core/internal/mediums/webrtc/session_description_wrapper.h" +#include "core/internal/mediums/webrtc/signaling_frames.h" +#include "platform/base/byte_array.h" +#include "platform/base/listeners.h" +#include "platform/public/cancelable_alarm.h" +#include "platform/public/future.h" +#include "platform/public/logging.h" +#include "platform/public/mutex_lock.h" #include "location/nearby/mediums/proto/web_rtc_signaling_frames.pb.h" #include "absl/strings/str_cat.h" #include "absl/time/time.h" @@ -50,6 +50,7 @@ bool WebRtc::IsAcceptingConnections() { } bool WebRtc::StartAcceptingConnections(const PeerId& self_id, + const LocationHint& location_hint, AcceptedConnectionCallback callback) { if (!IsAvailable()) { { @@ -73,11 +74,11 @@ bool WebRtc::StartAcceptingConnections(const PeerId& self_id, return false; } - if (!InitWebRtcFlow(Role::kOfferer, self_id)) return false; + if (!InitWebRtcFlow(Role::kOfferer, self_id, location_hint)) return false; restart_receive_messages_alarm_ = CancelableAlarm( "restart_receiving_messages_webrtc", - std::bind(&WebRtc::RestartReceiveMessages, this), + std::bind(&WebRtc::RestartReceiveMessages, this, location_hint), kRestartReceiveMessagesDuration, &restart_receive_messages_executor_); SessionDescriptionWrapper offer = connection_flow_->CreateOffer(); @@ -98,7 +99,8 @@ bool WebRtc::StartAcceptingConnections(const PeerId& self_id, return true; } -WebRtcSocketWrapper WebRtc::Connect(const PeerId& peer_id) { +WebRtcSocketWrapper WebRtc::Connect(const PeerId& peer_id, + const LocationHint& location_hint) { if (!IsAvailable()) { Disconnect(); return WebRtcSocketWrapper(); @@ -115,7 +117,7 @@ WebRtcSocketWrapper WebRtc::Connect(const PeerId& peer_id) { } peer_id_ = peer_id; - if (!InitWebRtcFlow(Role::kAnswerer, PeerId::FromRandom())) { + if (!InitWebRtcFlow(Role::kAnswerer, PeerId::FromRandom(), location_hint)) { return WebRtcSocketWrapper(); } } @@ -206,7 +208,8 @@ WebRtcSocketWrapper WebRtc::CreateWebRtcSocketWrapper( return WebRtcSocketWrapper(std::move(socket)); } -bool WebRtc::InitWebRtcFlow(Role role, const PeerId& self_id) { +bool WebRtc::InitWebRtcFlow(Role role, const PeerId& self_id, + const LocationHint& location_hint) { role_ = role; self_id_ = self_id; @@ -223,7 +226,8 @@ bool WebRtc::InitWebRtcFlow(Role role, const PeerId& self_id) { return false; } - signaling_messenger_ = medium_.GetSignalingMessenger(self_id_.GetId()); + signaling_messenger_ = + medium_.GetSignalingMessenger(self_id_.GetId(), location_hint); auto signaling_message_callback = [this](ByteArray message) { OffloadFromSignalingThread([this, message{std::move(message)}]() { ProcessSignalingMessage(message); @@ -469,7 +473,7 @@ void WebRtc::OffloadFromSignalingThread(Runnable runnable) { single_thread_executor_.Execute(std::move(runnable)); } -void WebRtc::RestartReceiveMessages() { +void WebRtc::RestartReceiveMessages(const LocationHint& location_hint) { if (!IsAcceptingConnections()) { NEARBY_LOG(INFO, "Skipping restart since we are not accepting connections."); @@ -481,7 +485,8 @@ void WebRtc::RestartReceiveMessages() { MutexLock lock(&mutex_); signaling_messenger_->StopReceivingMessages(); - signaling_messenger_ = medium_.GetSignalingMessenger(self_id_.GetId()); + signaling_messenger_ = + medium_.GetSignalingMessenger(self_id_.GetId(), location_hint); auto signaling_message_callback = [this](ByteArray message) { OffloadFromSignalingThread([this, message{std::move(message)}]() { diff --git a/cpp/core/internal/mediums/webrtc.h b/cpp/core/internal/mediums/webrtc.h new file mode 100644 index 00000000..92f3d95e --- /dev/null +++ b/cpp/core/internal/mediums/webrtc.h @@ -0,0 +1,174 @@ +#ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_H_ +#define CORE_INTERNAL_MEDIUMS_WEBRTC_H_ + +#include +#include + +#include "core/internal/mediums/webrtc/connection_flow.h" +#include "core/internal/mediums/webrtc/data_channel_listener.h" +#include "core/internal/mediums/webrtc/local_ice_candidate_listener.h" +#include "core/internal/mediums/webrtc/peer_id.h" +#include "core/internal/mediums/webrtc/webrtc_socket.h" +#include "core/internal/mediums/webrtc/webrtc_socket_wrapper.h" +#include "proto/connections/offline_wire_formats.pb.h" +#include "proto/connections/offline_wire_formats.pb.h" +#include "platform/base/byte_array.h" +#include "platform/base/listeners.h" +#include "platform/base/runnable.h" +#include "platform/public/atomic_boolean.h" +#include "platform/public/cancelable_alarm.h" +#include "platform/public/future.h" +#include "platform/public/mutex.h" +#include "platform/public/scheduled_executor.h" +#include "platform/public/single_thread_executor.h" +#include "platform/public/webrtc.h" +#include "location/nearby/mediums/proto/web_rtc_signaling_frames.pb.h" +#include "webrtc/api/data_channel_interface.h" +#include "webrtc/api/jsep.h" +#include "webrtc/api/scoped_refptr.h" + +namespace location { +namespace nearby { +namespace connections { +namespace mediums { + +// Callback that is invoked when a new connection is accepted. +struct AcceptedConnectionCallback { + std::function accepted_cb = + DefaultCallback(); +}; + +// Entry point for connecting a data channel between two devices via WebRtc. +class WebRtc { + public: + WebRtc(); + ~WebRtc(); + + // Returns if WebRtc is available as a medium for nearby to transport data. + // Runs on @MainThread. + bool IsAvailable(); + + // Returns if the device is ready to accept connections from remote devices. + // Runs on @MainThread. + bool IsAcceptingConnections() ABSL_LOCKS_EXCLUDED(mutex_); + + // Prepares the device to accept incoming WebRtc connections. Returns a + // boolean value indicating if the device has started accepting connections. + // Runs on @MainThread. + bool StartAcceptingConnections(const PeerId& self_id, + const LocationHint& location_hint, + AcceptedConnectionCallback callback) + ABSL_LOCKS_EXCLUDED(mutex_); + + // Prevents device from accepting future connections until + // StartAcceptingConnections() is called. + // Runs on @MainThread. + void StopAcceptingConnections() ABSL_LOCKS_EXCLUDED(mutex_); + + // Initiates a WebRtc connection with peer device identified by |peer_id|. + // Runs on @MainThread. + WebRtcSocketWrapper Connect(const PeerId& peer_id, + const LocationHint& location_hint) + ABSL_LOCKS_EXCLUDED(mutex_); + + private: + enum class Role { + kNone = 0, + kOfferer = 1, + kAnswerer = 2, + }; + + bool InitWebRtcFlow(Role role, const PeerId& self_id, + const LocationHint& location_hint) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Future ListenForWebRtcSocketFuture( + Future> + data_channel_future, + AcceptedConnectionCallback callback); + + WebRtcSocketWrapper CreateWebRtcSocketWrapper( + rtc::scoped_refptr data_channel); + + LocalIceCandidateListener GetLocalIceCandidateListener(); + void OnLocalIceCandidate( + const webrtc::IceCandidateInterface* local_ice_candidate); + + DataChannelListener GetDataChannelListener(); + void OnDataChannelClosed(); + void OnDataChannelMessageReceived(const ByteArray& message); + void OnDataChannelBufferedAmountChanged(); + + // Runs on @MainThread and |single_thread_executor_|. + bool SetLocalSessionDescription(SessionDescriptionWrapper sdp) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Runs on |single_thread_executor_|. + bool IsSignaling() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Runs on |single_thread_executor_|. + void ProcessSignalingMessage(const ByteArray& message) + ABSL_LOCKS_EXCLUDED(mutex_); + + // Runs on |single_thread_executor_|. + void SendOfferAndIceCandidatesToPeer() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Runs on |single_thread_executor_|. + void SendAnswerToPeer() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Runs on @MainThread and |single_thread_executor_|. + void LogAndDisconnect(const std::string& error_message) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Runs on @MainThread. + void Disconnect() ABSL_LOCKS_EXCLUDED(mutex_); + + // Runs on @MainThread and |single_thread_executor_|. + void DisconnectLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + void LogAndShutdownSignaling(const std::string& error_message) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Runs on @MainThread and |single_thread_executor_|. + void ShutdownSignaling() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Runs on @MainThread and |single_thread_executor_|. + void ShutdownWebRtcSocket() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Runs on @MainThread and |single_thread_executor_|. + void ShutdownIceCandidateCollection(); + + void OffloadFromSignalingThread(Runnable runnable); + + // Runs on |restart_receive_messages_executor_|. + void RestartReceiveMessages(const LocationHint& location_hint) + ABSL_LOCKS_EXCLUDED(mutex_); + + Mutex mutex_; + + Role role_ ABSL_GUARDED_BY(mutex_) = Role::kNone; + PeerId self_id_ ABSL_GUARDED_BY(mutex_); + PeerId peer_id_ ABSL_GUARDED_BY(mutex_); + ByteArray pending_local_offer_ ABSL_GUARDED_BY(mutex_); + std::vector<::location::nearby::mediums::IceCandidate> + pending_local_ice_candidates_ ABSL_GUARDED_BY(mutex_); + + WebRtcMedium medium_; + std::unique_ptr connection_flow_; + std::unique_ptr signaling_messenger_ + ABSL_GUARDED_BY(mutex_); + WebRtcSocketWrapper socket_ ABSL_GUARDED_BY(mutex_); + + SingleThreadExecutor single_thread_executor_; + + // Restarts the signaling messenger for receiving messages. + ScheduledExecutor restart_receive_messages_executor_; + CancelableAlarm restart_receive_messages_alarm_; +}; + +} // namespace mediums +} // namespace connections +} // namespace nearby +} // namespace location + +#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_H_ diff --git a/cpp/core_v2/internal/mediums/webrtc.h b/cpp/core/internal/mediums/webrtc.h.orig similarity index 91% rename from cpp/core_v2/internal/mediums/webrtc.h rename to cpp/core/internal/mediums/webrtc.h.orig index 4c09e319..a2456020 100644 --- a/cpp/core_v2/internal/mediums/webrtc.h +++ b/cpp/core/internal/mediums/webrtc.h.orig @@ -10,6 +10,8 @@ #include "core_v2/internal/mediums/webrtc/peer_id.h" #include "core_v2/internal/mediums/webrtc/webrtc_socket.h" #include "core_v2/internal/mediums/webrtc/webrtc_socket_wrapper.h" +#include "proto/connections/offline_wire_formats.pb.h" +#include "proto/connections/offline_wire_formats.pb.h" #include "platform_v2/base/byte_array.h" #include "platform_v2/base/listeners.h" #include "platform_v2/base/runnable.h" @@ -54,6 +56,7 @@ class WebRtc { // boolean value indicating if the device has started accepting connections. // Runs on @MainThread. bool StartAcceptingConnections(const PeerId& self_id, + const LocationHint& location_hint, AcceptedConnectionCallback callback) ABSL_LOCKS_EXCLUDED(mutex_); @@ -64,7 +67,8 @@ class WebRtc { // Initiates a WebRtc connection with peer device identified by |peer_id|. // Runs on @MainThread. - WebRtcSocketWrapper Connect(const PeerId& peer_id) + WebRtcSocketWrapper Connect(const PeerId& peer_id, + const LocationHint& location_hint) ABSL_LOCKS_EXCLUDED(mutex_); private: @@ -74,7 +78,8 @@ class WebRtc { kAnswerer = 2, }; - bool InitWebRtcFlow(Role role, const PeerId& self_id) + bool InitWebRtcFlow(Role role, const PeerId& self_id, + const LocationHint& location_hint) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); Future ListenForWebRtcSocketFuture( @@ -136,7 +141,8 @@ class WebRtc { void OffloadFromSignalingThread(Runnable runnable); // Runs on |restart_receive_messages_executor_|. - void RestartReceiveMessages() ABSL_LOCKS_EXCLUDED(mutex_); + void RestartReceiveMessages(const LocationHint& location_hint) + ABSL_LOCKS_EXCLUDED(mutex_); Mutex mutex_; diff --git a/cpp/core/internal/mediums/webrtc/BUILD b/cpp/core/internal/mediums/webrtc/BUILD index 56cf5608..cb614815 100644 --- a/cpp/core/internal/mediums/webrtc/BUILD +++ b/cpp/core/internal/mediums/webrtc/BUILD @@ -1,77 +1,63 @@ cc_library( name = "webrtc", - hdrs = [ + srcs = [ + "connection_flow.cc", + "data_channel_observer_impl.cc", + "peer_connection_observer_impl.cc", + "peer_id.cc", + "signaling_frames.cc", "webrtc_socket.cc", + ], + hdrs = [ + "connection_flow.h", + "data_channel_listener.h", + "data_channel_observer_impl.h", + "local_ice_candidate_listener.h", + "peer_connection_observer_impl.h", + "peer_id.h", + "session_description_wrapper.h", + "signaling_frames.h", "webrtc_socket.h", + "webrtc_socket_wrapper.h", + ], + visibility = [ + "//core/internal:__subpackages__", ], deps = [ - "//platform:utils", - "//platform/api", + "//core:core_types", + "//core/internal/mediums:utils", + "//platform/base", + "//platform/public:comm", + "//platform/public:logging", + "//platform/public:types", + "//location/nearby/mediums/proto:web_rtc_signaling_frames_cc_proto", + "//absl/memory", + "//absl/strings", + "//absl/time", "//webrtc/api:libjingle_peerconnection_api", ], ) cc_test( name = "webrtc_test", - srcs = ["webrtc_socket_test.cc"], + srcs = [ + "connection_flow_test.cc", + "peer_id_test.cc", + "signaling_frames_test.cc", + "webrtc_socket_test.cc", + ], deps = [ ":webrtc", - "//platform:types", - "//platform/api", - "//platform/impl/g3", # buildcleaner: keep - "//testing/base/public:gunit_main", - "//webrtc/api:libjingle_peerconnection_api", - ], -) - -cc_library( - name = "peer_id", - srcs = ["peer_id.cc"], - hdrs = ["peer_id.h"], - deps = [ - "//core/internal/mediums:utils", - "//platform:types", - "//platform/api", - "//platform/port:string", - "//absl/strings", - ], -) - -cc_library( - name = "signaling_frames", - srcs = ["signaling_frames.cc"], - hdrs = ["signaling_frames.h"], - deps = [ - ":peer_id", - "//platform:types", - "//location/nearby/mediums/proto:web_rtc_signaling_frames_cc_proto", - "//webrtc/api:libjingle_peerconnection_api", - ], -) - -cc_test( - name = "peer_id_test", - srcs = ["peer_id_test.cc"], - deps = [ - ":peer_id", - "//platform:types", - "//platform/api", - "//platform/impl/g3", # buildcleaner: keep - "//testing/base/public:gunit_main", - "//absl/strings", - ], -) - -cc_test( - name = "signaling_frames_test", - srcs = ["signaling_frames_test.cc"], - deps = [ - ":peer_id", - ":signaling_frames", - "//platform:types", + "//platform/base", + "//platform/base:test_util", "//platform/impl/g3", # buildcleaner: keep + "//platform/public:comm", + "//platform/public:types", "//net/proto2/public:proto2", "//testing/base/public:gunit_main", - "//webrtc/pc:peerconnection", # buildcleaner: keep + "//absl/time", + "//webrtc/api:libjingle_peerconnection_api", + "//webrtc/api:rtc_error", + "//webrtc/api:scoped_refptr", ], ) diff --git a/cpp/core_v2/internal/mediums/webrtc/connection_flow.cc b/cpp/core/internal/mediums/webrtc/connection_flow.cc similarity index 97% rename from cpp/core_v2/internal/mediums/webrtc/connection_flow.cc rename to cpp/core/internal/mediums/webrtc/connection_flow.cc index 3950f8c4..fb724487 100644 --- a/cpp/core_v2/internal/mediums/webrtc/connection_flow.cc +++ b/cpp/core/internal/mediums/webrtc/connection_flow.cc @@ -1,12 +1,12 @@ -#include "core_v2/internal/mediums/webrtc/connection_flow.h" +#include "core/internal/mediums/webrtc/connection_flow.h" #include #include -#include "core_v2/internal/mediums/webrtc/session_description_wrapper.h" -#include "platform_v2/public/logging.h" -#include "platform_v2/public/mutex_lock.h" -#include "platform_v2/public/webrtc.h" +#include "core/internal/mediums/webrtc/session_description_wrapper.h" +#include "platform/public/logging.h" +#include "platform/public/mutex_lock.h" +#include "platform/public/webrtc.h" #include "absl/memory/memory.h" #include "absl/time/time.h" #include "webrtc/api/data_channel_interface.h" diff --git a/cpp/core_v2/internal/mediums/webrtc/connection_flow.h b/cpp/core/internal/mediums/webrtc/connection_flow.h similarity index 88% rename from cpp/core_v2/internal/mediums/webrtc/connection_flow.h rename to cpp/core/internal/mediums/webrtc/connection_flow.h index b1e76c41..47fbb58f 100644 --- a/cpp/core_v2/internal/mediums/webrtc/connection_flow.h +++ b/cpp/core/internal/mediums/webrtc/connection_flow.h @@ -1,17 +1,17 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_WEBRTC_CONNECTION_FLOW_H_ -#define CORE_V2_INTERNAL_MEDIUMS_WEBRTC_CONNECTION_FLOW_H_ +#ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_CONNECTION_FLOW_H_ +#define CORE_INTERNAL_MEDIUMS_WEBRTC_CONNECTION_FLOW_H_ #include -#include "core_v2/internal/mediums/webrtc/data_channel_listener.h" -#include "core_v2/internal/mediums/webrtc/data_channel_observer_impl.h" -#include "core_v2/internal/mediums/webrtc/local_ice_candidate_listener.h" -#include "core_v2/internal/mediums/webrtc/peer_connection_observer_impl.h" -#include "core_v2/internal/mediums/webrtc/session_description_wrapper.h" -#include "platform_v2/base/runnable.h" -#include "platform_v2/public/future.h" -#include "platform_v2/public/single_thread_executor.h" -#include "platform_v2/public/webrtc.h" +#include "core/internal/mediums/webrtc/data_channel_listener.h" +#include "core/internal/mediums/webrtc/data_channel_observer_impl.h" +#include "core/internal/mediums/webrtc/local_ice_candidate_listener.h" +#include "core/internal/mediums/webrtc/peer_connection_observer_impl.h" +#include "core/internal/mediums/webrtc/session_description_wrapper.h" +#include "platform/base/runnable.h" +#include "platform/public/future.h" +#include "platform/public/single_thread_executor.h" +#include "platform/public/webrtc.h" #include "webrtc/api/data_channel_interface.h" #include "webrtc/api/peer_connection_interface.h" @@ -157,4 +157,4 @@ class ConnectionFlow { } // namespace nearby } // namespace location -#endif // CORE_V2_INTERNAL_MEDIUMS_WEBRTC_CONNECTION_FLOW_H_ +#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_CONNECTION_FLOW_H_ diff --git a/cpp/core_v2/internal/mediums/webrtc/connection_flow_test.cc b/cpp/core/internal/mediums/webrtc/connection_flow_test.cc similarity index 96% rename from cpp/core_v2/internal/mediums/webrtc/connection_flow_test.cc rename to cpp/core/internal/mediums/webrtc/connection_flow_test.cc index c9767dff..6dec5c59 100644 --- a/cpp/core_v2/internal/mediums/webrtc/connection_flow_test.cc +++ b/cpp/core/internal/mediums/webrtc/connection_flow_test.cc @@ -1,12 +1,12 @@ -#include "core_v2/internal/mediums/webrtc/connection_flow.h" +#include "core/internal/mediums/webrtc/connection_flow.h" #include #include -#include "core_v2/internal/mediums/webrtc/session_description_wrapper.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/medium_environment.h" -#include "platform_v2/public/webrtc.h" +#include "core/internal/mediums/webrtc/session_description_wrapper.h" +#include "platform/base/byte_array.h" +#include "platform/base/medium_environment.h" +#include "platform/public/webrtc.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/time/time.h" diff --git a/cpp/core_v2/internal/mediums/webrtc/data_channel_listener.h b/cpp/core/internal/mediums/webrtc/data_channel_listener.h similarity index 72% rename from cpp/core_v2/internal/mediums/webrtc/data_channel_listener.h rename to cpp/core/internal/mediums/webrtc/data_channel_listener.h index 20baef2a..319889fd 100644 --- a/cpp/core_v2/internal/mediums/webrtc/data_channel_listener.h +++ b/cpp/core/internal/mediums/webrtc/data_channel_listener.h @@ -1,8 +1,8 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_WEBRTC_DATA_CHANNEL_LISTENER_H_ -#define CORE_V2_INTERNAL_MEDIUMS_WEBRTC_DATA_CHANNEL_LISTENER_H_ +#ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_DATA_CHANNEL_LISTENER_H_ +#define CORE_INTERNAL_MEDIUMS_WEBRTC_DATA_CHANNEL_LISTENER_H_ -#include "core_v2/listeners.h" -#include "platform_v2/base/byte_array.h" +#include "core/listeners.h" +#include "platform/base/byte_array.h" namespace location { namespace nearby { @@ -28,4 +28,4 @@ struct DataChannelListener { } // namespace nearby } // namespace location -#endif // CORE_V2_INTERNAL_MEDIUMS_WEBRTC_DATA_CHANNEL_LISTENER_H_ +#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_DATA_CHANNEL_LISTENER_H_ diff --git a/cpp/core_v2/internal/mediums/webrtc/data_channel_observer_impl.cc b/cpp/core/internal/mediums/webrtc/data_channel_observer_impl.cc similarity index 92% rename from cpp/core_v2/internal/mediums/webrtc/data_channel_observer_impl.cc rename to cpp/core/internal/mediums/webrtc/data_channel_observer_impl.cc index cf048ab7..ca46199b 100644 --- a/cpp/core_v2/internal/mediums/webrtc/data_channel_observer_impl.cc +++ b/cpp/core/internal/mediums/webrtc/data_channel_observer_impl.cc @@ -1,4 +1,4 @@ -#include "core_v2/internal/mediums/webrtc/data_channel_observer_impl.h" +#include "core/internal/mediums/webrtc/data_channel_observer_impl.h" namespace location { namespace nearby { diff --git a/cpp/core_v2/internal/mediums/webrtc/data_channel_observer_impl.h b/cpp/core/internal/mediums/webrtc/data_channel_observer_impl.h similarity index 76% rename from cpp/core_v2/internal/mediums/webrtc/data_channel_observer_impl.h rename to cpp/core/internal/mediums/webrtc/data_channel_observer_impl.h index f7508c1a..4cb6d277 100644 --- a/cpp/core_v2/internal/mediums/webrtc/data_channel_observer_impl.h +++ b/cpp/core/internal/mediums/webrtc/data_channel_observer_impl.h @@ -1,7 +1,7 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_WEBRTC_DATA_CHANNEL_OBSERVER_IMPL_H_ -#define CORE_V2_INTERNAL_MEDIUMS_WEBRTC_DATA_CHANNEL_OBSERVER_IMPL_H_ +#ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_DATA_CHANNEL_OBSERVER_IMPL_H_ +#define CORE_INTERNAL_MEDIUMS_WEBRTC_DATA_CHANNEL_OBSERVER_IMPL_H_ -#include "core_v2/internal/mediums/webrtc/data_channel_listener.h" +#include "core/internal/mediums/webrtc/data_channel_listener.h" #include "webrtc/api/data_channel_interface.h" namespace location { @@ -32,4 +32,4 @@ class DataChannelObserverImpl : public webrtc::DataChannelObserver { } // namespace nearby } // namespace location -#endif // CORE_V2_INTERNAL_MEDIUMS_WEBRTC_DATA_CHANNEL_OBSERVER_IMPL_H_ +#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_DATA_CHANNEL_OBSERVER_IMPL_H_ diff --git a/cpp/core_v2/internal/mediums/webrtc/local_ice_candidate_listener.h b/cpp/core/internal/mediums/webrtc/local_ice_candidate_listener.h similarity index 70% rename from cpp/core_v2/internal/mediums/webrtc/local_ice_candidate_listener.h rename to cpp/core/internal/mediums/webrtc/local_ice_candidate_listener.h index 62adf483..dc4c9a42 100644 --- a/cpp/core_v2/internal/mediums/webrtc/local_ice_candidate_listener.h +++ b/cpp/core/internal/mediums/webrtc/local_ice_candidate_listener.h @@ -1,7 +1,7 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_WEBRTC_LOCAL_ICE_CANDIDATE_LISTENER_H_ -#define CORE_V2_INTERNAL_MEDIUMS_WEBRTC_LOCAL_ICE_CANDIDATE_LISTENER_H_ +#ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_LOCAL_ICE_CANDIDATE_LISTENER_H_ +#define CORE_INTERNAL_MEDIUMS_WEBRTC_LOCAL_ICE_CANDIDATE_LISTENER_H_ -#include "core_v2/listeners.h" +#include "core/listeners.h" #include "webrtc/api/peer_connection_interface.h" namespace location { @@ -22,4 +22,4 @@ struct LocalIceCandidateListener { } // namespace nearby } // namespace location -#endif // CORE_V2_INTERNAL_MEDIUMS_WEBRTC_LOCAL_ICE_CANDIDATE_LISTENER_H_ +#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_LOCAL_ICE_CANDIDATE_LISTENER_H_ diff --git a/cpp/core_v2/internal/mediums/webrtc/peer_connection_observer_impl.cc b/cpp/core/internal/mediums/webrtc/peer_connection_observer_impl.cc similarity index 92% rename from cpp/core_v2/internal/mediums/webrtc/peer_connection_observer_impl.cc rename to cpp/core/internal/mediums/webrtc/peer_connection_observer_impl.cc index f44e3d7d..a86a1eaa 100644 --- a/cpp/core_v2/internal/mediums/webrtc/peer_connection_observer_impl.cc +++ b/cpp/core/internal/mediums/webrtc/peer_connection_observer_impl.cc @@ -1,7 +1,7 @@ -#include "core_v2/internal/mediums/webrtc/peer_connection_observer_impl.h" +#include "core/internal/mediums/webrtc/peer_connection_observer_impl.h" -#include "core_v2/internal/mediums/webrtc/connection_flow.h" -#include "platform_v2/public/logging.h" +#include "core/internal/mediums/webrtc/connection_flow.h" +#include "platform/public/logging.h" namespace location { namespace nearby { diff --git a/cpp/core_v2/internal/mediums/webrtc/peer_connection_observer_impl.h b/cpp/core/internal/mediums/webrtc/peer_connection_observer_impl.h similarity index 79% rename from cpp/core_v2/internal/mediums/webrtc/peer_connection_observer_impl.h rename to cpp/core/internal/mediums/webrtc/peer_connection_observer_impl.h index a46be455..a8aee854 100644 --- a/cpp/core_v2/internal/mediums/webrtc/peer_connection_observer_impl.h +++ b/cpp/core/internal/mediums/webrtc/peer_connection_observer_impl.h @@ -1,8 +1,8 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_WEBRTC_PEER_CONNECTION_OBSERVER_IMPL_H_ -#define CORE_V2_INTERNAL_MEDIUMS_WEBRTC_PEER_CONNECTION_OBSERVER_IMPL_H_ +#ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_PEER_CONNECTION_OBSERVER_IMPL_H_ +#define CORE_INTERNAL_MEDIUMS_WEBRTC_PEER_CONNECTION_OBSERVER_IMPL_H_ -#include "core_v2/internal/mediums/webrtc/local_ice_candidate_listener.h" -#include "platform_v2/public/single_thread_executor.h" +#include "core/internal/mediums/webrtc/local_ice_candidate_listener.h" +#include "platform/public/single_thread_executor.h" #include "webrtc/api/peer_connection_interface.h" namespace location { @@ -44,4 +44,4 @@ class PeerConnectionObserverImpl : public webrtc::PeerConnectionObserver { } // namespace nearby } // namespace location -#endif // CORE_V2_INTERNAL_MEDIUMS_WEBRTC_PEER_CONNECTION_OBSERVER_IMPL_H_ +#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_PEER_CONNECTION_OBSERVER_IMPL_H_ diff --git a/cpp/core/internal/mediums/webrtc/peer_id.cc b/cpp/core/internal/mediums/webrtc/peer_id.cc index d6c03fe6..513ae9d6 100644 --- a/cpp/core/internal/mediums/webrtc/peer_id.cc +++ b/cpp/core/internal/mediums/webrtc/peer_id.cc @@ -14,27 +14,26 @@ namespace mediums { namespace { constexpr int kPeerIdLength = 64; -std::string BytesToStringUppercase(ConstPtr bytes) { +std::string BytesToStringUppercase(const ByteArray& bytes) { std::string hex_string( - absl::BytesToHexString(std::string(bytes->getData(), bytes->size()))); + absl::BytesToHexString(std::string(bytes.data(), bytes.size()))); absl::AsciiStrToUpper(&hex_string); return hex_string; } } // namespace -ConstPtr PeerId::FromRandom(Ptr hash_utils) { - return FromSeed(Utils::generateRandomBytes(kPeerIdLength), hash_utils); +PeerId PeerId::FromRandom() { + return FromSeed(Utils::GenerateRandomBytes(kPeerIdLength)); } -ConstPtr PeerId::FromSeed(ConstPtr seed, - Ptr hash_utils) { - ScopedPtr> full_hash( - Utils::sha256Hash(hash_utils, seed, kPeerIdLength)); - ScopedPtr> hashedSeed( - MakeConstPtr(new ByteArray(full_hash->getData(), kPeerIdLength / 2))); - return MakeConstPtr(new PeerId(BytesToStringUppercase(hashedSeed.get()))); +PeerId PeerId::FromSeed(const ByteArray& seed) { + ByteArray full_hash(Utils::Sha256Hash(seed, kPeerIdLength)); + ByteArray hashed_seed(full_hash.data(), kPeerIdLength / 2); + return PeerId(BytesToStringUppercase(hashed_seed)); } +bool PeerId::IsValid() const { return !id_.empty(); } + } // namespace mediums } // namespace connections } // namespace nearby diff --git a/cpp/core/internal/mediums/webrtc/peer_id.h b/cpp/core/internal/mediums/webrtc/peer_id.h index 1f559c5a..a52c6b5d 100644 --- a/cpp/core/internal/mediums/webrtc/peer_id.h +++ b/cpp/core/internal/mediums/webrtc/peer_id.h @@ -1,10 +1,10 @@ #ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_PEER_ID_H_ #define CORE_INTERNAL_MEDIUMS_WEBRTC_PEER_ID_H_ -#include "platform/api/hash_utils.h" -#include "platform/byte_array.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include +#include + +#include "platform/base/byte_array.h" namespace location { namespace nearby { @@ -12,20 +12,22 @@ namespace connections { namespace mediums { // PeerId is used as an identifier to exchange SDP messages to establish WebRTC -// p2p connection. +// p2p connection. An empty PeerId is considered to be invalid. class PeerId { public: + PeerId() = default; explicit PeerId(const std::string& id) : id_(id) {} ~PeerId() = default; - static ConstPtr FromRandom(Ptr hash_utils); - static ConstPtr FromSeed(ConstPtr seed, - Ptr hash_utils); + static PeerId FromRandom(); + static PeerId FromSeed(const ByteArray& seed); + + bool IsValid() const; const std::string& GetId() const { return id_; } private: - const std::string id_; + std::string id_; }; } // namespace mediums diff --git a/cpp/core/internal/mediums/webrtc/peer_id_test.cc b/cpp/core/internal/mediums/webrtc/peer_id_test.cc index de1235e9..3cbac2eb 100644 --- a/cpp/core/internal/mediums/webrtc/peer_id_test.cc +++ b/cpp/core/internal/mediums/webrtc/peer_id_test.cc @@ -1,73 +1,39 @@ #include "core/internal/mediums/webrtc/peer_id.h" -#include "platform/api/hash_utils.h" -#include "platform/byte_array.h" -#include "platform/ptr.h" +#include + +#include "platform/base/byte_array.h" +#include "platform/public/crypto.h" #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/strings/escaping.h" namespace location { namespace nearby { namespace connections { namespace mediums { -namespace { - -class MockHashUtils : public HashUtils { - public: - MOCK_METHOD(ConstPtr, md5, (const std::string& input), (override)); - MOCK_METHOD(ConstPtr, sha256, (const std::string& input), - (override)); -}; - -} // namespace - TEST(PeerIdTest, GenerateRandomPeerId) { - // These are actual SHA-256 values for |seed| = "seed". - std::string hashed_output = - "19b25856e1c150ca834cffc8b59b23adbd0ec0389e58eb22b3b64768098d002b"; - std::string expected_peer_id = - "19B25856E1C150CA834CFFC8B59B23ADBD0EC0389E58EB22B3B64768098D002B"; - - Ptr> mock_hash_utils( - MakePtr(new MockHashUtils())); - ON_CALL(*mock_hash_utils.get(), sha256(testing::_)) - .WillByDefault(testing::Return( - MakeConstPtr(new ByteArray(absl::HexStringToBytes(hashed_output))))); - EXPECT_CALL(*mock_hash_utils.get(), sha256(testing::_)); - - ConstPtr peer_id = PeerId::FromRandom(mock_hash_utils); - ASSERT_EQ(64, peer_id->GetId().size()); - ASSERT_EQ(expected_peer_id, peer_id->GetId()); + PeerId peer_id = PeerId::FromRandom(); + EXPECT_EQ(64, peer_id.GetId().size()); } TEST(PeerIdTest, GenerateFromSeed) { // Values calculated by running actual SHA-256 hash on |seed|. - std::string seed = "sesdfed"; - std::string hashed_output = - "19b25856e1c150ca834cffc8b59b23adbd0ec0389e58eb22b3b64768098d002b"; + std::string seed = "seed"; std::string expected_peer_id = "19B25856E1C150CA834CFFC8B59B23ADBD0EC0389E58EB22B3B64768098D002B"; - Ptr> mock_hash_utils( - MakePtr(new MockHashUtils())); - ON_CALL(*mock_hash_utils.get(), sha256(testing::Eq(seed))) - .WillByDefault(testing::Return( - MakeConstPtr(new ByteArray(absl::HexStringToBytes(hashed_output))))); - EXPECT_CALL(*mock_hash_utils.get(), sha256(testing::Eq(seed))); + ByteArray seed_bytes(seed); + PeerId peer_id = PeerId::FromSeed(seed_bytes); - ConstPtr peer_id = - PeerId::FromSeed(MakeConstPtr(new ByteArray(seed)), mock_hash_utils); - - ASSERT_EQ(64, peer_id->GetId().size()); - ASSERT_EQ(expected_peer_id, peer_id->GetId()); + EXPECT_EQ(64, peer_id.GetId().size()); + EXPECT_EQ(expected_peer_id, peer_id.GetId()); } TEST(PeerIdTest, GetId) { const std::string id = "this_is_a_test"; PeerId peer_id(id); - ASSERT_EQ(id, peer_id.GetId()); + EXPECT_EQ(id, peer_id.GetId()); } } // namespace mediums diff --git a/cpp/core_v2/internal/mediums/webrtc/session_description_wrapper.h b/cpp/core/internal/mediums/webrtc/session_description_wrapper.h similarity index 88% rename from cpp/core_v2/internal/mediums/webrtc/session_description_wrapper.h rename to cpp/core/internal/mediums/webrtc/session_description_wrapper.h index 1c566deb..fd597e0e 100644 --- a/cpp/core_v2/internal/mediums/webrtc/session_description_wrapper.h +++ b/cpp/core/internal/mediums/webrtc/session_description_wrapper.h @@ -1,5 +1,5 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_WEBRTC_SESSION_DESCRIPTION_WRAPPER_H_ -#define CORE_V2_INTERNAL_MEDIUMS_WEBRTC_SESSION_DESCRIPTION_WRAPPER_H_ +#ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_SESSION_DESCRIPTION_WRAPPER_H_ +#define CORE_INTERNAL_MEDIUMS_WEBRTC_SESSION_DESCRIPTION_WRAPPER_H_ #include "webrtc/api/peer_connection_interface.h" @@ -47,4 +47,4 @@ class SessionDescriptionWrapper { std::unique_ptr impl_; }; -#endif // CORE_V2_INTERNAL_MEDIUMS_WEBRTC_SESSION_DESCRIPTION_WRAPPER_H_ +#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_SESSION_DESCRIPTION_WRAPPER_H_ diff --git a/cpp/core/internal/mediums/webrtc/signaling_frames.cc b/cpp/core/internal/mediums/webrtc/signaling_frames.cc index 6af39230..0de3718f 100644 --- a/cpp/core/internal/mediums/webrtc/signaling_frames.cc +++ b/cpp/core/internal/mediums/webrtc/signaling_frames.cc @@ -4,44 +4,43 @@ namespace location { namespace nearby { namespace connections { namespace mediums { - namespace webrtc_frames { using WebRtcSignalingFrame = location::nearby::mediums::WebRtcSignalingFrame; namespace { -ConstPtr FrameToByteArray( - const WebRtcSignalingFrame& signaling_frame) { +ByteArray FrameToByteArray(const WebRtcSignalingFrame& signaling_frame) { std::string message; signaling_frame.SerializeToString(&message); - return MakeConstPtr(new ByteArray(message.c_str(), message.size())); + return ByteArray(message.c_str(), message.size()); } -void SetSenderId(ConstPtr sender_id, WebRtcSignalingFrame& frame) { - frame.mutable_sender_id()->set_id(sender_id->GetId()); +void SetSenderId(const PeerId& sender_id, WebRtcSignalingFrame& frame) { + frame.mutable_sender_id()->set_id(sender_id.GetId()); } -ConstPtr DecodeIceCandidate( - const location::nearby::mediums::IceCandidate& ice_candidate_proto) { +std::unique_ptr DecodeIceCandidate( + location::nearby::mediums::IceCandidate ice_candidate_proto) { webrtc::SdpParseError error; - return ConstPtr(webrtc::CreateIceCandidate( - ice_candidate_proto.sdp_mid(), ice_candidate_proto.sdp_m_line_index(), - ice_candidate_proto.sdp(), &error)); + return std::unique_ptr( + webrtc::CreateIceCandidate(ice_candidate_proto.sdp_mid(), + ice_candidate_proto.sdp_m_line_index(), + ice_candidate_proto.sdp(), &error)); } } // namespace -ConstPtr EncodeReadyForSignalingPoke(ConstPtr sender_id) { +ByteArray EncodeReadyForSignalingPoke(const PeerId& sender_id) { WebRtcSignalingFrame signaling_frame; signaling_frame.set_type(WebRtcSignalingFrame::READY_FOR_SIGNALING_POKE_TYPE); SetSenderId(sender_id, signaling_frame); - signaling_frame.mutable_ready_for_signaling_poke(); + signaling_frame.set_allocated_ready_for_signaling_poke( + new location::nearby::mediums::ReadyForSignalingPoke()); return FrameToByteArray(std::move(signaling_frame)); } -ConstPtr EncodeOffer( - ConstPtr sender_id, - const webrtc::SessionDescriptionInterface& offer) { +ByteArray EncodeOffer(const PeerId& sender_id, + const webrtc::SessionDescriptionInterface& offer) { WebRtcSignalingFrame signaling_frame; signaling_frame.set_type(WebRtcSignalingFrame::OFFER_TYPE); SetSenderId(sender_id, signaling_frame); @@ -53,9 +52,8 @@ ConstPtr EncodeOffer( return FrameToByteArray(std::move(signaling_frame)); } -ConstPtr EncodeAnswer( - ConstPtr sender_id, - const webrtc::SessionDescriptionInterface& answer) { +ByteArray EncodeAnswer(const PeerId& sender_id, + const webrtc::SessionDescriptionInterface& answer) { WebRtcSignalingFrame signaling_frame; signaling_frame.set_type(WebRtcSignalingFrame::ANSWER_TYPE); SetSenderId(sender_id, signaling_frame); @@ -67,8 +65,8 @@ ConstPtr EncodeAnswer( return FrameToByteArray(std::move(signaling_frame)); } -ConstPtr EncodeIceCandidates( - ConstPtr sender_id, +ByteArray EncodeIceCandidates( + const PeerId& sender_id, const std::vector& ice_candidates) { WebRtcSignalingFrame signaling_frame; @@ -81,25 +79,23 @@ ConstPtr EncodeIceCandidates( return FrameToByteArray(std::move(signaling_frame)); } -Ptr DecodeOffer( +std::unique_ptr DecodeOffer( const WebRtcSignalingFrame& frame) { - return MakePtr(webrtc::CreateSessionDescription( - webrtc::SdpType::kOffer, - frame.offer().session_description().description()) - .release()); + return webrtc::CreateSessionDescription( + webrtc::SdpType::kOffer, + frame.offer().session_description().description()); } -Ptr DecodeAnswer( +std::unique_ptr DecodeAnswer( const WebRtcSignalingFrame& frame) { - return MakePtr(webrtc::CreateSessionDescription( - webrtc::SdpType::kAnswer, - frame.answer().session_description().description()) - .release()); + return webrtc::CreateSessionDescription( + webrtc::SdpType::kAnswer, + frame.answer().session_description().description()); } -std::vector> DecodeIceCandidates( +std::vector> DecodeIceCandidates( const WebRtcSignalingFrame& frame) { - std::vector> ice_candidates; + std::vector> ice_candidates; for (const auto& candidate : frame.ice_candidates().ice_candidates()) { ice_candidates.push_back(DecodeIceCandidate(candidate)); } @@ -118,7 +114,6 @@ location::nearby::mediums::IceCandidate EncodeIceCandidate( } } // namespace webrtc_frames - } // namespace mediums } // namespace connections } // namespace nearby diff --git a/cpp/core/internal/mediums/webrtc/signaling_frames.h b/cpp/core/internal/mediums/webrtc/signaling_frames.h index fb885a58..847072e1 100644 --- a/cpp/core/internal/mediums/webrtc/signaling_frames.h +++ b/cpp/core/internal/mediums/webrtc/signaling_frames.h @@ -4,8 +4,7 @@ #include #include "core/internal/mediums/webrtc/peer_id.h" -#include "platform/byte_array.h" -#include "platform/ptr.h" +#include "platform/base/byte_array.h" #include "location/nearby/mediums/proto/web_rtc_signaling_frames.pb.h" #include "webrtc/api/peer_connection_interface.h" @@ -13,34 +12,30 @@ namespace location { namespace nearby { namespace connections { namespace mediums { - namespace webrtc_frames { -ConstPtr EncodeReadyForSignalingPoke(ConstPtr sender_id); +ByteArray EncodeReadyForSignalingPoke(const PeerId& sender_id); -ConstPtr EncodeOffer( - ConstPtr sender_id, - const webrtc::SessionDescriptionInterface& offer); -ConstPtr EncodeAnswer( - ConstPtr sender_id, - const webrtc::SessionDescriptionInterface& answer); +ByteArray EncodeOffer(const PeerId& sender_id, + const webrtc::SessionDescriptionInterface& offer); +ByteArray EncodeAnswer(const PeerId& sender_id, + const webrtc::SessionDescriptionInterface& answer); -ConstPtr EncodeIceCandidates( - ConstPtr sender_id, +ByteArray EncodeIceCandidates( + const PeerId& sender_id, const std::vector& ice_candidates); location::nearby::mediums::IceCandidate EncodeIceCandidate( const webrtc::IceCandidateInterface& ice_candidate); -Ptr DecodeOffer( +std::unique_ptr DecodeOffer( const location::nearby::mediums::WebRtcSignalingFrame& frame); -Ptr DecodeAnswer( +std::unique_ptr DecodeAnswer( const location::nearby::mediums::WebRtcSignalingFrame& frame); -std::vector> DecodeIceCandidates( +std::vector> DecodeIceCandidates( const location::nearby::mediums::WebRtcSignalingFrame& frame); } // namespace webrtc_frames - } // namespace mediums } // namespace connections } // namespace nearby diff --git a/cpp/core/internal/mediums/webrtc/signaling_frames_test.cc b/cpp/core/internal/mediums/webrtc/signaling_frames_test.cc index 4cc4df2e..47594e6d 100644 --- a/cpp/core/internal/mediums/webrtc/signaling_frames_test.cc +++ b/cpp/core/internal/mediums/webrtc/signaling_frames_test.cc @@ -3,7 +3,6 @@ #include #include "core/internal/mediums/webrtc/peer_id.h" -#include "platform/ptr.h" #include "net/proto2/public/text_format.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -67,12 +66,11 @@ const char kIceCandidatesProto[] = R"( } // namespace TEST(SignalingFramesTest, SignalingPoke) { - ConstPtr sender_id(new PeerId("abc")); - ConstPtr encoded_poke = EncodeReadyForSignalingPoke(sender_id); + PeerId sender_id("abc"); + ByteArray encoded_poke = EncodeReadyForSignalingPoke(sender_id); location::nearby::mediums::WebRtcSignalingFrame frame; - frame.ParseFromString( - std::string(encoded_poke->getData(), encoded_poke->size())); + frame.ParseFromString(std::string(encoded_poke.data(), encoded_poke.size())); EXPECT_THAT(frame, testing::EqualsProto(R"( sender_id { id: "abc" } @@ -82,22 +80,23 @@ TEST(SignalingFramesTest, SignalingPoke) { } TEST(SignalingFramesTest, EncodeValidOffer) { - ConstPtr sender_id(new PeerId("abc")); + PeerId sender_id("abc"); std::unique_ptr offer = webrtc::CreateSessionDescription(webrtc::SdpType::kOffer, kSampleSdp); - ConstPtr encoded_offer = EncodeOffer(sender_id, *offer); + ByteArray encoded_offer = EncodeOffer(sender_id, *offer); location::nearby::mediums::WebRtcSignalingFrame frame; frame.ParseFromString( - std::string(encoded_offer->getData(), encoded_offer->size())); + std::string(encoded_offer.data(), encoded_offer.size())); EXPECT_THAT(frame, testing::EqualsProto(kOfferProto)); } -TEST(SignalingFramesTest, DecodeValidOffer) { +TEST(SignaingFramesTest, DecodeValidOffer) { location::nearby::mediums::WebRtcSignalingFrame frame; - proto2::TextFormat::ParseFromStringPiece(kOfferProto, &frame); - Ptr decoded_offer = DecodeOffer(frame); + proto2::TextFormat::ParseFromString(kOfferProto, &frame); + std::unique_ptr decoded_offer = + DecodeOffer(frame); EXPECT_EQ(webrtc::SdpType::kOffer, decoded_offer->GetType()); std::string description; @@ -106,22 +105,23 @@ TEST(SignalingFramesTest, DecodeValidOffer) { } TEST(SignalingFramesTest, EncodeValidAnswer) { - ConstPtr sender_id(new PeerId("abc")); - std::unique_ptr answer = - webrtc::CreateSessionDescription(webrtc::SdpType::kAnswer, kSampleSdp); - ConstPtr encoded_answer = EncodeAnswer(sender_id, *answer); + PeerId sender_id("abc"); + std::unique_ptr answer( + webrtc::CreateSessionDescription(webrtc::SdpType::kAnswer, kSampleSdp)); + ByteArray encoded_answer = EncodeAnswer(sender_id, *answer); location::nearby::mediums::WebRtcSignalingFrame frame; frame.ParseFromString( - std::string(encoded_answer->getData(), encoded_answer->size())); + std::string(encoded_answer.data(), encoded_answer.size())); EXPECT_THAT(frame, testing::EqualsProto(kAnswerProto)); } TEST(SignalingFramesTest, DecodeValidAnswer) { location::nearby::mediums::WebRtcSignalingFrame frame; - proto2::TextFormat::ParseFromStringPiece(kAnswerProto, &frame); - Ptr decoded_answer = DecodeAnswer(frame); + proto2::TextFormat::ParseFromString(kAnswerProto, &frame); + std::unique_ptr decoded_answer = + DecodeAnswer(frame); EXPECT_EQ(webrtc::SdpType::kAnswer, decoded_answer->GetType()); std::string description; @@ -130,42 +130,40 @@ TEST(SignalingFramesTest, DecodeValidAnswer) { } TEST(SignalingFramesTest, EncodeValidIceCandidates) { - ConstPtr sender_id(new PeerId("abc")); + PeerId sender_id("abc"); webrtc::SdpParseError error; - std::vector> ice_candidates; + std::vector> ice_candidates; ice_candidates.emplace_back(webrtc::CreateIceCandidate( kIceSdpMid, kIceSdpMLineIndex, kIceCandidateSdp1, &error)); ice_candidates.emplace_back(webrtc::CreateIceCandidate( kIceSdpMid, kIceSdpMLineIndex, kIceCandidateSdp2, &error)); std::vector encoded_candidates_vec; for (const auto& ice_candidate : ice_candidates) { - encoded_candidates_vec.push_back(EncodeIceCandidate(*ice_candidate.get())); + encoded_candidates_vec.push_back(EncodeIceCandidate(*ice_candidate)); } - ConstPtr encoded_candidates = + ByteArray encoded_candidates = EncodeIceCandidates(sender_id, encoded_candidates_vec); location::nearby::mediums::WebRtcSignalingFrame frame; frame.ParseFromString( - std::string(encoded_candidates->getData(), encoded_candidates->size())); + std::string(encoded_candidates.data(), encoded_candidates.size())); EXPECT_THAT(frame, testing::EqualsProto(kIceCandidatesProto)); } TEST(SignalingFramesTest, DecodeValidIceCandidates) { webrtc::SdpParseError error; - - std::vector> ice_candidates; + std::vector> ice_candidates; ice_candidates.emplace_back(webrtc::CreateIceCandidate( kIceSdpMid, kIceSdpMLineIndex, kIceCandidateSdp1, &error)); ice_candidates.emplace_back(webrtc::CreateIceCandidate( kIceSdpMid, kIceSdpMLineIndex, kIceCandidateSdp2, &error)); - std::vector encoded_candidates_vec; location::nearby::mediums::WebRtcSignalingFrame frame; - proto2::TextFormat::ParseFromStringPiece(kIceCandidatesProto, &frame); - std::vector> decoded_candidates = - DecodeIceCandidates(frame); + proto2::TextFormat::ParseFromString(kIceCandidatesProto, &frame); + std::vector> + decoded_candidates = DecodeIceCandidates(frame); ASSERT_EQ(2u, decoded_candidates.size()); for (int i = 0; i < static_cast(decoded_candidates.size()); i++) { diff --git a/cpp/core/internal/mediums/webrtc/webrtc_socket.cc b/cpp/core/internal/mediums/webrtc/webrtc_socket.cc index 80dd1ce6..159cfaed 100644 --- a/cpp/core/internal/mediums/webrtc/webrtc_socket.cc +++ b/cpp/core/internal/mediums/webrtc/webrtc_socket.cc @@ -1,6 +1,7 @@ #include "core/internal/mediums/webrtc/webrtc_socket.h" -#include "platform/synchronized.h" +#include "platform/public/logging.h" +#include "platform/public/mutex_lock.h" namespace location { namespace nearby { @@ -8,128 +9,89 @@ namespace connections { namespace mediums { // OutputStreamImpl -template -Exception::Value WebRtcSocket::OutputStreamImpl::write( - ConstPtr data) { - ScopedPtr> scoped_data(data); - - if (scoped_data->size() > kMaxDataSize) { +Exception WebRtcSocket::OutputStreamImpl::Write(const ByteArray& data) { + if (data.size() > kMaxDataSize) { NEARBY_LOG(WARNING, "Sending data larger than 1MB"); - return Exception::IO; + return {Exception::kIo}; } - socket_->BlockUntilSufficientSpaceInBuffer(scoped_data->size()); + socket_->BlockUntilSufficientSpaceInBuffer(data.size()); if (socket_->IsClosed()) { NEARBY_LOG(WARNING, "Tried sending message while socket is closed"); - return Exception::IO; + return {Exception::kIo}; } - if (!socket_->SendMessage(scoped_data.release())) { - return Exception::IO; + if (!socket_->SendMessage(data)) { + return {Exception::kIo}; } - return Exception::NONE; + return {Exception::kSuccess}; } -template -Exception::Value WebRtcSocket::OutputStreamImpl::flush() { +Exception WebRtcSocket::OutputStreamImpl::Flush() { // Java implementation is empty. - return Exception::NONE; + return {Exception::kSuccess}; } -template -Exception::Value WebRtcSocket::OutputStreamImpl::close() { - socket_->close(); - return Exception::NONE; +Exception WebRtcSocket::OutputStreamImpl::Close() { + socket_->Close(); + return {Exception::kSuccess}; } // WebRtcSocket -template -WebRtcSocket::WebRtcSocket( +WebRtcSocket::WebRtcSocket( const std::string& name, rtc::scoped_refptr data_channel) - : name_(name), - data_channel_(std::move(data_channel)), - pipe_(MakeRefCountedPtr(new Pipe())), - incoming_data_piped_input_stream_(Pipe::createInputStream(pipe_)), - incoming_data_piped_output_stream_(Pipe::createOutputStream(pipe_)), - output_stream_(MakePtr(new OutputStreamImpl(this))), - closed_(Platform::createAtomicBoolean(false)), - backpressure_lock_(Platform::createLock()), - buffer_variable_( - Platform::createConditionVariable(backpressure_lock_.get())) {} + : name_(name), data_channel_(std::move(data_channel)) {} -template -Ptr WebRtcSocket::getInputStream() { - return incoming_data_piped_input_stream_.get(); -} +InputStream& WebRtcSocket::GetInputStream() { return pipe_.GetInputStream(); } -template -Ptr WebRtcSocket::getOutputStream() { - return output_stream_.get(); -} +OutputStream& WebRtcSocket::GetOutputStream() { return output_stream_; } -template -void WebRtcSocket::close() { +void WebRtcSocket::Close() { if (IsClosed()) return; - closed_->set(true); - incoming_data_piped_output_stream_->close(); - incoming_data_piped_input_stream_->close(); + closed_.Set(true); + pipe_.GetInputStream().Close(); + pipe_.GetOutputStream().Close(); data_channel_->Close(); WakeUpWriter(); - if (!socket_closed_listener_.isNull()) { - socket_closed_listener_->OnSocketClosed(); + socket_closed_listener_.socket_closed_cb(); +} + +void WebRtcSocket::NotifyDataChannelMsgReceived(const ByteArray& message) { + if (!pipe_.GetOutputStream().Write(message).Ok()) { + Close(); + return; } + + if (!pipe_.GetOutputStream().Flush().Ok()) Close(); } -template -void WebRtcSocket::NotifyDataChannelMsgReceived( - ConstPtr message) { - Exception::Value exception = - incoming_data_piped_output_stream_->write(message); - if (exception != Exception::NONE) close(); +void WebRtcSocket::NotifyDataChannelBufferedAmountChanged() { WakeUpWriter(); } - exception = incoming_data_piped_output_stream_->flush(); - if (exception != Exception::NONE) close(); +bool WebRtcSocket::SendMessage(const ByteArray& data) { + return data_channel_->Send( + webrtc::DataBuffer(std::string(data.data(), data.size()))); } -template -void WebRtcSocket::NotifyDataChannelBufferedAmountChanged() { - WakeUpWriter(); +bool WebRtcSocket::IsClosed() { return closed_.Get(); } + +void WebRtcSocket::WakeUpWriter() { + MutexLock lock(&backpressure_mutex_); + buffer_variable_.Notify(); } -template -bool WebRtcSocket::SendMessage(ConstPtr data) { - ScopedPtr> scoped_data(data); - return data_channel_->Send(webrtc::DataBuffer( - std::string(scoped_data->getData(), scoped_data->size()))); +void WebRtcSocket::SetOnSocketClosedListener(SocketClosedListener&& listener) { + socket_closed_listener_ = std::move(listener); } -template -bool WebRtcSocket::IsClosed() { - return closed_->get(); -} - -template -void WebRtcSocket::WakeUpWriter() { - Synchronized s(backpressure_lock_.get()); - buffer_variable_->notify(); -} - -template -void WebRtcSocket::SetOnSocketClosedListener( - Ptr listener) { - socket_closed_listener_ = listener; -} - -template -void WebRtcSocket::BlockUntilSufficientSpaceInBuffer(int length) { - Synchronized s(backpressure_lock_.get()); +void WebRtcSocket::BlockUntilSufficientSpaceInBuffer(int length) { + MutexLock lock(&backpressure_mutex_); while (!IsClosed() && (data_channel_->buffered_amount() + length > kMaxDataSize)) { // TODO(himanshujaju): Add wait with timeout. - buffer_variable_->wait(); + buffer_variable_.Wait(); } } diff --git a/cpp/core/internal/mediums/webrtc/webrtc_socket.h b/cpp/core/internal/mediums/webrtc/webrtc_socket.h index 4351cadf..5e62befd 100644 --- a/cpp/core/internal/mediums/webrtc/webrtc_socket.h +++ b/cpp/core/internal/mediums/webrtc/webrtc_socket.h @@ -1,13 +1,17 @@ #ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_H_ #define CORE_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_H_ -#include "platform/api/atomic_boolean.h" -#include "platform/api/input_stream.h" -#include "platform/api/output_stream.h" -#include "platform/api/socket.h" -#include "platform/pipe.h" -#include "webrtc/api/data_channel_interface.h" +#include +#include "core/listeners.h" +#include "platform/base/input_stream.h" +#include "platform/base/output_stream.h" +#include "platform/base/socket.h" +#include "platform/public/atomic_boolean.h" +#include "platform/public/condition_variable.h" +#include "platform/public/mutex.h" +#include "platform/public/pipe.h" +#include "webrtc/api/data_channel_interface.h" namespace location { namespace nearby { namespace connections { @@ -21,7 +25,6 @@ constexpr int kMaxDataSize = 1 * 1024 * 1024; // // Messages are buffered here to prevent the data channel from overflowing, // which could lead to data loss. -template class WebRtcSocket : public Socket { public: WebRtcSocket(const std::string& name, @@ -32,66 +35,62 @@ class WebRtcSocket : public Socket { WebRtcSocket& operator=(const WebRtcSocket& other) = delete; // Overrides for location::nearby::Socket: - Ptr getInputStream() override; - Ptr getOutputStream() override; - void close() override; + InputStream& GetInputStream() override; + OutputStream& GetOutputStream() override; + void Close() override; // Callback from WebRTC data channel when new message has been received from // the remote. - void NotifyDataChannelMsgReceived(ConstPtr message); + void NotifyDataChannelMsgReceived(const ByteArray& message); // Callback from WebRTC data channel that the buffered data amount has // changed. void NotifyDataChannelBufferedAmountChanged(); // Listener class the gets called when the socket is closed. - class SocketClosedListener { - public: - virtual ~SocketClosedListener() = default; - virtual void OnSocketClosed() = 0; + struct SocketClosedListener { + std::function socket_closed_cb = DefaultCallback<>(); }; - void SetOnSocketClosedListener(Ptr listener); + + void SetOnSocketClosedListener(SocketClosedListener&& listener); private: class OutputStreamImpl : public OutputStream { public: - explicit OutputStreamImpl(WebRtcSocket* const socket) - : socket_(socket) {} + explicit OutputStreamImpl(WebRtcSocket* const socket) : socket_(socket) {} ~OutputStreamImpl() override = default; OutputStreamImpl(const OutputStreamImpl& other) = delete; OutputStreamImpl& operator=(const OutputStreamImpl& other) = delete; // OutputStream: - Exception::Value write(ConstPtr data) override; - Exception::Value flush() override; - Exception::Value close() override; + Exception Write(const ByteArray& data) override; + Exception Flush() override; + Exception Close() override; private: // |this| OutputStreamImpl is owned by |socket_|. - WebRtcSocket* const socket_; + WebRtcSocket* const socket_; }; void WakeUpWriter(); bool IsClosed(); - bool SendMessage(ConstPtr data); + bool SendMessage(const ByteArray& data); void BlockUntilSufficientSpaceInBuffer(int length); std::string name_; rtc::scoped_refptr data_channel_; - Ptr pipe_; - ScopedPtr> incoming_data_piped_input_stream_; - ScopedPtr> incoming_data_piped_output_stream_; + Pipe pipe_; - ScopedPtr> output_stream_; + OutputStreamImpl output_stream_{this}; - ScopedPtr> closed_; + AtomicBoolean closed_{false}; - Ptr socket_closed_listener_; + SocketClosedListener socket_closed_listener_; - ScopedPtr> backpressure_lock_; - ScopedPtr> buffer_variable_; + mutable Mutex backpressure_mutex_; + ConditionVariable buffer_variable_{&backpressure_mutex_}; }; } // namespace mediums @@ -99,6 +98,4 @@ class WebRtcSocket : public Socket { } // namespace nearby } // namespace location -#include "core/internal/mediums/webrtc/webrtc_socket.cc" - #endif // CORE_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_H_ diff --git a/cpp/core/internal/mediums/webrtc/webrtc_socket_test.cc b/cpp/core/internal/mediums/webrtc/webrtc_socket_test.cc index be83d9f1..4760834c 100644 --- a/cpp/core/internal/mediums/webrtc/webrtc_socket_test.cc +++ b/cpp/core/internal/mediums/webrtc/webrtc_socket_test.cc @@ -1,8 +1,8 @@ #include "core/internal/mediums/webrtc/webrtc_socket.h" -#include "platform/api/platform.h" -#include "platform/byte_array.h" -#include "platform/ptr.h" +#include + +#include "platform/base/byte_array.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "webrtc/api/data_channel_interface.h" @@ -14,7 +14,7 @@ namespace mediums { namespace { -using TestPlatform = platform::ImplementationPlatform; +// using TestPlatform = platform::ImplementationPlatform; const char kSocketName[] = "TestSocket"; @@ -43,110 +43,109 @@ class MockDataChannel } // namespace -class MockSocketClosedListener - : public WebRtcSocket::SocketClosedListener { - public: - MOCK_METHOD(void, OnSocketClosed, ()); -}; - TEST(WebRtcSocketTest, ReadFromSocket) { - ConstPtr kMessage = MakeConstPtr(new ByteArray("Message")); + const ByteArray kMessage{"Message"}; rtc::scoped_refptr mock_data_channel = new MockDataChannel(); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); + WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); webrtc_socket.NotifyDataChannelMsgReceived(kMessage); - ExceptionOr> result = - webrtc_socket.getInputStream()->read(); + ExceptionOr result = webrtc_socket.GetInputStream().Read(7); EXPECT_TRUE(result.ok()); EXPECT_EQ(result.result(), kMessage); } TEST(WebRtcSocketTest, ReadMultipleMessages) { rtc::scoped_refptr mock_data_channel = new MockDataChannel(); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); + WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - webrtc_socket.NotifyDataChannelMsgReceived(MakeConstPtr(new ByteArray("Me"))); - webrtc_socket.NotifyDataChannelMsgReceived( - MakeConstPtr(new ByteArray("ssa"))); - webrtc_socket.NotifyDataChannelMsgReceived(MakeConstPtr(new ByteArray("ge"))); - ExceptionOr> result; + webrtc_socket.NotifyDataChannelMsgReceived(ByteArray{"Me"}); + webrtc_socket.NotifyDataChannelMsgReceived(ByteArray{"ssa"}); + webrtc_socket.NotifyDataChannelMsgReceived(ByteArray{"ge"}); + + ExceptionOr result; // This behaviour is different from the Java code - result = webrtc_socket.getInputStream()->read(); + result = webrtc_socket.GetInputStream().Read(7); EXPECT_TRUE(result.ok()); - EXPECT_EQ(result.result()->asString(), "Me"); + EXPECT_EQ(result.result(), ByteArray{"Me"}); - result = webrtc_socket.getInputStream()->read(); + result = webrtc_socket.GetInputStream().Read(7); EXPECT_TRUE(result.ok()); - EXPECT_EQ(result.result()->asString(), "ssa"); + EXPECT_EQ(result.result(), ByteArray{"ssa"}); - result = webrtc_socket.getInputStream()->read(); + result = webrtc_socket.GetInputStream().Read(7); EXPECT_TRUE(result.ok()); - EXPECT_EQ(result.result()->asString(), "ge"); + EXPECT_EQ(result.result(), ByteArray{"ge"}); } TEST(WebRtcSocketTest, WriteToSocket) { - ConstPtr kMessage = MakeConstPtr(new ByteArray("Message")); + const ByteArray kMessage{"Message"}; rtc::scoped_refptr mock_data_channel = new MockDataChannel(); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); + WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); EXPECT_CALL(*mock_data_channel, Send(testing::_)) .WillRepeatedly(testing::Return(true)); - EXPECT_EQ(webrtc_socket.getOutputStream()->write(kMessage), Exception::NONE); + EXPECT_TRUE(webrtc_socket.GetOutputStream().Write(kMessage).Ok()); } TEST(WebRtcSocketTest, SendDataBiggerThanMax) { - ConstPtr kMessage = MakeConstPtr(new ByteArray(kMaxDataSize + 1)); + const ByteArray kMessage{kMaxDataSize + 1}; rtc::scoped_refptr mock_data_channel = new MockDataChannel(); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); + WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); EXPECT_CALL(*mock_data_channel, Send(testing::_)).Times(0); - EXPECT_EQ(webrtc_socket.getOutputStream()->write(kMessage), Exception::IO); + EXPECT_EQ(webrtc_socket.GetOutputStream().Write(kMessage), + Exception{Exception::kIo}); } TEST(WebRtcSocketTest, WriteToDataChannelFails) { - ConstPtr kMessage = MakeConstPtr(new ByteArray("Message")); + ByteArray kMessage{"Message"}; rtc::scoped_refptr mock_data_channel = new MockDataChannel(); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); + WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); ON_CALL(*mock_data_channel, Send(testing::_)) .WillByDefault(testing::Return(false)); - EXPECT_EQ(webrtc_socket.getOutputStream()->write(kMessage), Exception::IO); + EXPECT_EQ(webrtc_socket.GetOutputStream().Write(kMessage), + Exception{Exception::kIo}); } TEST(WebRtcSocketTest, Close) { rtc::scoped_refptr mock_data_channel = new MockDataChannel(); - ScopedPtr> mock_listener( - MakePtr(new MockSocketClosedListener())); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - webrtc_socket.SetOnSocketClosedListener(mock_listener.get()); + WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - EXPECT_CALL(*mock_listener, OnSocketClosed()); EXPECT_CALL(*mock_data_channel, Close()); - webrtc_socket.close(); + + int socket_closed_cb_called = 0; + + webrtc_socket.SetOnSocketClosedListener( + {.socket_closed_cb = [&]() { socket_closed_cb_called++; }}); + webrtc_socket.Close(); + + EXPECT_EQ(socket_closed_cb_called, 1); } TEST(WebRtcSocketTest, WriteOnClosedChannel) { - ConstPtr kMessage = MakeConstPtr(new ByteArray("Message")); + ByteArray kMessage{"Message"}; rtc::scoped_refptr mock_data_channel = new MockDataChannel(); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - webrtc_socket.close(); + WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); + webrtc_socket.Close(); EXPECT_CALL(*mock_data_channel, Send(testing::_)).Times(0); - EXPECT_EQ(webrtc_socket.getOutputStream()->write(kMessage), Exception::IO); + EXPECT_EQ(webrtc_socket.GetOutputStream().Write(kMessage), + Exception{Exception::kIo}); } TEST(WebRtcSocketTest, ReadFromClosedChannel) { - ConstPtr kMessage = MakeConstPtr(new ByteArray("Message")); + ByteArray kMessage{"Message"}; rtc::scoped_refptr mock_data_channel = new MockDataChannel(); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); + WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); ON_CALL(*mock_data_channel, Send(testing::_)) .WillByDefault(testing::Return(true)); - webrtc_socket.getOutputStream()->write(kMessage); - webrtc_socket.close(); + webrtc_socket.GetOutputStream().Write(kMessage); + webrtc_socket.Close(); - EXPECT_EQ(webrtc_socket.getInputStream()->read().exception(), Exception::IO); + EXPECT_EQ(webrtc_socket.GetInputStream().Read(7).exception(), Exception::kIo); } } // namespace mediums diff --git a/cpp/core_v2/internal/mediums/webrtc/webrtc_socket_wrapper.h b/cpp/core/internal/mediums/webrtc/webrtc_socket_wrapper.h similarity index 81% rename from cpp/core_v2/internal/mediums/webrtc/webrtc_socket_wrapper.h rename to cpp/core/internal/mediums/webrtc/webrtc_socket_wrapper.h index e7cc89ee..34b0a638 100644 --- a/cpp/core_v2/internal/mediums/webrtc/webrtc_socket_wrapper.h +++ b/cpp/core/internal/mediums/webrtc/webrtc_socket_wrapper.h @@ -1,9 +1,9 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_WRAPPER_H_ -#define CORE_V2_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_WRAPPER_H_ +#ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_WRAPPER_H_ +#define CORE_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_WRAPPER_H_ #include -#include "core_v2/internal/mediums/webrtc/webrtc_socket.h" +#include "core/internal/mediums/webrtc/webrtc_socket.h" namespace location { namespace nearby { @@ -46,4 +46,4 @@ class WebRtcSocketWrapper final { } // namespace nearby } // namespace location -#endif // CORE_V2_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_WRAPPER_H_ +#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_WRAPPER_H_ diff --git a/cpp/core_v2/internal/mediums/webrtc_test.cc b/cpp/core/internal/mediums/webrtc_test.cc similarity index 80% rename from cpp/core_v2/internal/mediums/webrtc_test.cc rename to cpp/core/internal/mediums/webrtc_test.cc index 749f21c1..4874e105 100644 --- a/cpp/core_v2/internal/mediums/webrtc_test.cc +++ b/cpp/core/internal/mediums/webrtc_test.cc @@ -1,9 +1,9 @@ -#include "core_v2/internal/mediums/webrtc.h" +#include "core/internal/mediums/webrtc.h" -#include "core_v2/internal/mediums/webrtc/webrtc_socket_wrapper.h" -#include "platform_v2/base/listeners.h" -#include "platform_v2/base/medium_environment.h" -#include "platform_v2/public/mutex_lock.h" +#include "core/internal/mediums/webrtc/webrtc_socket_wrapper.h" +#include "platform/base/listeners.h" +#include "platform/base/medium_environment.h" +#include "platform/public/mutex_lock.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -38,12 +38,13 @@ TEST_F(WebRtcTest, StartAcceptingConnectionTwice) { WebRtc webrtc; PeerId self_id("peer_id"); + LocationHint location_hint{}; ASSERT_TRUE(webrtc.IsAvailable()); ASSERT_TRUE(webrtc.StartAcceptingConnections( - self_id, {mock_accepted_callback_.AsStdFunction()})); + self_id, location_hint, {mock_accepted_callback_.AsStdFunction()})); EXPECT_FALSE(webrtc.StartAcceptingConnections( - self_id, {mock_accepted_callback_.AsStdFunction()})); + self_id, location_hint, {mock_accepted_callback_.AsStdFunction()})); EXPECT_TRUE(webrtc.IsAcceptingConnections()); } @@ -52,13 +53,14 @@ TEST_F(WebRtcTest, StartAcceptingConnectionTwice) { TEST_F(WebRtcTest, Connect_DataChannelTimeOut) { WebRtc webrtc; PeerId peer_id("peer_id"); + LocationHint location_hint; ASSERT_TRUE(webrtc.IsAvailable()); - WebRtcSocketWrapper wrapper_1 = webrtc.Connect(peer_id); + WebRtcSocketWrapper wrapper_1 = webrtc.Connect(peer_id, location_hint); EXPECT_FALSE(wrapper_1.IsValid()); - EXPECT_TRUE( - webrtc.StartAcceptingConnections(peer_id, AcceptedConnectionCallback())); + EXPECT_TRUE(webrtc.StartAcceptingConnections(peer_id, location_hint, + AcceptedConnectionCallback())); } // Tests the flow when the device calls Connect() after calling @@ -70,15 +72,17 @@ TEST_F(WebRtcTest, StartAcceptingConnection_ThenConnect) { WebRtc webrtc; PeerId self_id("peer_id"); + LocationHint location_hint; ASSERT_TRUE(webrtc.IsAvailable()); ASSERT_TRUE(webrtc.StartAcceptingConnections( - self_id, {mock_accepted_callback_.AsStdFunction()})); - WebRtcSocketWrapper wrapper = webrtc.Connect(PeerId("random_peer_id")); + self_id, location_hint, {mock_accepted_callback_.AsStdFunction()})); + WebRtcSocketWrapper wrapper = + webrtc.Connect(PeerId("random_peer_id"), location_hint); EXPECT_TRUE(webrtc.IsAcceptingConnections()); EXPECT_FALSE(wrapper.IsValid()); EXPECT_FALSE(webrtc.StartAcceptingConnections( - self_id, {mock_accepted_callback_.AsStdFunction()})); + self_id, location_hint, {mock_accepted_callback_.AsStdFunction()})); } // Tests the flow when the device calls StartAcceptingConnections but the medium @@ -90,10 +94,11 @@ TEST_F(WebRtcTest, StartAndStopAcceptingConnections) { WebRtc webrtc; PeerId self_id("peer_id"); + LocationHint location_hint; ASSERT_TRUE(webrtc.IsAvailable()); ASSERT_TRUE(webrtc.StartAcceptingConnections( - self_id, {mock_accepted_callback_.AsStdFunction()})); + self_id, location_hint, {mock_accepted_callback_.AsStdFunction()})); webrtc.StopAcceptingConnections(); EXPECT_FALSE(webrtc.IsAcceptingConnections()); } @@ -104,11 +109,12 @@ TEST_F(WebRtcTest, ConnectTwice) { WebRtc receiver, sender, device_c; WebRtcSocketWrapper receiver_socket, sender_socket; const PeerId self_id("self_id"), other_id("other_id"); + LocationHint location_hint; Future connected; ByteArray message("message xyz"); receiver.StartAcceptingConnections( - self_id, + self_id, location_hint, {[&receiver_socket, connected](WebRtcSocketWrapper wrapper) mutable { receiver_socket = wrapper; connected.Set(receiver_socket.IsValid()); @@ -117,17 +123,17 @@ TEST_F(WebRtcTest, ConnectTwice) { using MockAcceptedCallback = testing::MockFunction; testing::StrictMock mock_accepted_callback_; - device_c.StartAcceptingConnections(other_id, + device_c.StartAcceptingConnections(other_id, location_hint, {mock_accepted_callback_.AsStdFunction()}); - sender_socket = sender.Connect(self_id); + sender_socket = sender.Connect(self_id, location_hint); EXPECT_TRUE(sender_socket.IsValid()); ExceptionOr devices_connected = connected.Get(); ASSERT_TRUE(devices_connected.ok()); EXPECT_TRUE(devices_connected.result()); - WebRtcSocketWrapper socket = sender.Connect(other_id); + WebRtcSocketWrapper socket = sender.Connect(other_id, location_hint); EXPECT_FALSE(socket.IsValid()); EXPECT_TRUE(receiver_socket.IsValid()); @@ -148,17 +154,18 @@ TEST_F(WebRtcTest, ConnectBothDevicesAndAbort) { WebRtc receiver, sender; WebRtcSocketWrapper receiver_socket, sender_socket; const PeerId self_id("self_id"); + LocationHint location_hint; Future connected; ByteArray message("message xyz"); receiver.StartAcceptingConnections( - self_id, + self_id, location_hint, {[&receiver_socket, connected](WebRtcSocketWrapper wrapper) mutable { receiver_socket = wrapper; connected.Set(receiver_socket.IsValid()); }}); - sender_socket = sender.Connect(self_id); + sender_socket = sender.Connect(self_id, location_hint); EXPECT_TRUE(sender_socket.IsValid()); ExceptionOr devices_connected = connected.Get(); @@ -174,17 +181,18 @@ TEST_F(WebRtcTest, ConnectBothDevicesAndSendData) { WebRtc receiver, sender; WebRtcSocketWrapper receiver_socket, sender_socket; const PeerId self_id("self_id"); + LocationHint location_hint; Future connected; ByteArray message("message"); receiver.StartAcceptingConnections( - self_id, + self_id, location_hint, {[&receiver_socket, connected](WebRtcSocketWrapper wrapper) mutable { receiver_socket = wrapper; connected.Set(receiver_socket.IsValid()); }}); - sender_socket = sender.Connect(self_id); + sender_socket = sender.Connect(self_id, location_hint); EXPECT_TRUE(sender_socket.IsValid()); ExceptionOr devices_connected = connected.Get(); @@ -206,17 +214,18 @@ TEST_F(WebRtcTest, ConnectBothDevices_ShutdownSignaling_SendData) { WebRtc receiver, sender; WebRtcSocketWrapper receiver_socket, sender_socket; const PeerId self_id("self_id"); + LocationHint location_hint; Future connected; ByteArray message("message xyz"); receiver.StartAcceptingConnections( - self_id, + self_id, location_hint, {[&receiver_socket, connected](WebRtcSocketWrapper wrapper) mutable { receiver_socket = wrapper; connected.Set(receiver_socket.IsValid()); }}); - sender_socket = sender.Connect(self_id); + sender_socket = sender.Connect(self_id, location_hint); EXPECT_TRUE(sender_socket.IsValid()); ExceptionOr devices_connected = connected.Get(); @@ -243,10 +252,11 @@ TEST_F(WebRtcTest, StartAcceptingConnections_NullPeerConnection) { WebRtc webrtc; PeerId self_id("peer_id"); + LocationHint location_hint; ASSERT_TRUE(webrtc.IsAvailable()); EXPECT_FALSE(webrtc.StartAcceptingConnections( - self_id, {mock_accepted_callback_.AsStdFunction()})); + self_id, location_hint, {mock_accepted_callback_.AsStdFunction()})); } TEST_F(WebRtcTest, Connect_NullPeerConnection) { @@ -259,9 +269,11 @@ TEST_F(WebRtcTest, Connect_NullPeerConnection) { WebRtc webrtc; PeerId self_id("peer_id"); + LocationHint location_hint; ASSERT_TRUE(webrtc.IsAvailable()); - WebRtcSocketWrapper wrapper = webrtc.Connect(PeerId("random_peer_id")); + WebRtcSocketWrapper wrapper = + webrtc.Connect(PeerId("random_peer_id"), location_hint); EXPECT_FALSE(wrapper.IsValid()); } diff --git a/cpp/core/internal/mediums/wifi_lan.cc b/cpp/core/internal/mediums/wifi_lan.cc index bc69220a..af607cbd 100644 --- a/cpp/core/internal/mediums/wifi_lan.cc +++ b/cpp/core/internal/mediums/wifi_lan.cc @@ -1,213 +1,248 @@ #include "core/internal/mediums/wifi_lan.h" -#include "platform/synchronized.h" +#include +#include +#include + +#include "platform/public/logging.h" +#include "platform/public/mutex_lock.h" namespace location { namespace nearby { namespace connections { -namespace mediums { -template -WifiLan::WifiLan() - : lock_(Platform::createLock()), - wifi_lan_medium_(Platform::createWifiLanMedium()) {} +bool WifiLan::IsAvailable() const { + MutexLock lock(&mutex_); -template -bool WifiLan::IsAvailable() { - Synchronized s(lock_.get()); - - return !wifi_lan_medium_.isNull(); + return IsAvailableLocked(); } -template -bool WifiLan::StartAdvertising( - absl::string_view service_id, - absl::string_view wifi_lan_service_info_name) { - Synchronized s(lock_.get()); +bool WifiLan::IsAvailableLocked() const { return medium_.IsValid(); } - if (!IsAvailable()) { +bool WifiLan::StartAdvertising(const std::string& service_id, + const std::string& service_info_name, + const std::string& endpoint_info_name) { + MutexLock lock(&mutex_); + + if (service_info_name.empty()) { + NEARBY_LOG( + INFO, + "Refusing to turn on WifiLan advertising. Empty service info name."); return false; } - // TODO(b/149806065): Implements platform wifi-lan medium. - // wifi_lan_medium_->StartAdvertising(service_id, - // wifi_lan_service_info_name)); - - advertising_info_.service_id.assign(service_id.data()); - return false; -} - -template -void WifiLan::StopAdvertising(absl::string_view service_id) { - Synchronized s(lock_.get()); - - if (!IsAdvertising()) { - return; + if (!IsAvailableLocked()) { + NEARBY_LOG(INFO, + "Can't turn on WifiLan advertising. WifiLan is not available."); + return false; } - // TODO(b/149806065): Implements platform wifi-lan medium. - // wifi_lan_medium_->StopAdvertising(advertising_info_.service_id); + if (!medium_.StartAdvertising(service_id, service_info_name, + endpoint_info_name)) { + NEARBY_LOG( + INFO, "Failed to turn on WifiLan advertising with service info name=%s", + service_info_name.c_str()); + return false; + } + + NEARBY_LOGS(INFO) << "Turned on WifiLan advertising with service info name=" + << service_info_name << ", service id=" << service_id; + advertising_info_.Add(service_id); + return true; +} + +bool WifiLan::StopAdvertising(const std::string& service_id) { + MutexLock lock(&mutex_); + + if (!IsAdvertisingLocked(service_id)) { + NEARBY_LOG(INFO, "Can't turn off WifiLan advertising; it is already off"); + return false; + } + + NEARBY_LOG(INFO, "Turned off WifiLan advertising with service id=%s", + service_id.c_str()); + bool ret = medium_.StopAdvertising(service_id); // Reset our bundle of advertising state to mark that we're no longer // advertising. - advertising_info_.service_id.clear(); + advertising_info_.Remove(service_id); + return ret; } -template -bool WifiLan::IsAdvertising() { - Synchronized s(lock_.get()); +bool WifiLan::IsAdvertising(const std::string& service_id) { + MutexLock lock(&mutex_); - return !advertising_info_.service_id.empty(); + return IsAdvertisingLocked(service_id); } -template -bool WifiLan::StartDiscovery( - absl::string_view service_id, - Ptr discovered_service_callback) { - Synchronized s(lock_.get()); +bool WifiLan::IsAdvertisingLocked(const std::string& service_id) { + return advertising_info_.Existed(service_id); +} - if (discovered_service_callback.isNull() || service_id.empty()) { - // TODO(b/149806065): logger.atSevere().log("Refusing to start WifiLan - // discovering because a null parameter was passed in."); +bool WifiLan::StartDiscovery(const std::string& service_id, + DiscoveredServiceCallback callback) { + MutexLock lock(&mutex_); + + if (service_id.empty()) { + NEARBY_LOG(INFO, + "Refusing to start WifiLan discovering with empty service id."); return false; } - if (IsDiscovering(service_id)) { - // TODO(b/149806065): logger.atSevere().log("Refusing to start WifiLan - // discovering because we are already discovering."); + if (!IsAvailableLocked()) { + NEARBY_LOG( + INFO, + "Can't discover WifiLan services because WifiLan isn't available."); return false; } - if (!IsAvailable()) { - // TODO(b/149806065): logger.atSevere().log("Can't start WifiLan discovering - // because WifiLan isn't available."); + if (IsDiscoveringLocked(service_id)) { + NEARBY_LOG( + INFO, + "Refusing to start discovery of WifiLan services because another " + "discovery is already in-progress."); return false; } - // Avoid leaks. - ScopedPtr> - scoped_discovered_service_callback_bridge( - new DiscoveredServiceCallbackBridge(discovered_service_callback)); + if (!medium_.StartDiscovery(service_id, callback)) { + NEARBY_LOG(INFO, "Failed to start discovery of WifiLan services."); + return false; + } - // TODO(b/149806065): Implements platform wifi-lan medium. - // A possible implementation is: - // wifi_lan_medium_->StartDiscovery( - // service_id, Ptr( - // discovered_service_callback_bridge.release())); - - discovering_info_.service_id.assign(service_id.data()); - return false; + NEARBY_LOG(INFO, "Turned on WifiLan discovering with service id=%s", + service_id.c_str()); + // Mark the fact that we're currently performing a WifiLan discovering. + discovering_info_.Add(service_id); + return true; } -template -void WifiLan::StopDiscovery(absl::string_view service_id) { - Synchronized s(lock_.get()); +bool WifiLan::StopDiscovery(const std::string& service_id) { + MutexLock lock(&mutex_); - if (!IsDiscovering(service_id)) { - // TODO(b/149806065): logger.atDebug().log("Can't turn off WifiLan - // discovering because we never started discovering."); - return; - } - - // TODO(b/149806065): Implements platform wifi-lan medium. - // wifi_lan_medium_->StopDiscovery(discovering_info_.service_id); - // Reset our bundle of scanning state to mark that we're no longer scanning. - discovering_info_.service_id.clear(); -} - -template -bool WifiLan::IsDiscovering(absl::string_view service_id) { - Synchronized s(lock_.get()); - - return !discovering_info_.service_id.empty(); -} - -template -bool WifiLan::StartAcceptingConnections( - absl::string_view service_id, - Ptr accepted_connection_callback) { - Synchronized s(lock_.get()); - - if (accepted_connection_callback.isNull() || service_id.empty()) { - // TODO(b/149806065): logger.atSevere().log("Refusing to start accepting - // WifiLan connections because a null parameter was passed in."); + if (!IsDiscoveringLocked(service_id)) { + NEARBY_LOG(INFO, + "Can't turn off WifiLan discovering because we never started " + "discovering."); return false; } - if (IsAcceptingConnections(service_id)) { - // TODO(b/149806065): logger.atSevere().log("Refusing to start accepting - // WifiLan connections for %s because another WifiLan service socket is - // already in-progress.", service_id); - return false; - } - - if (!IsAvailable()) { - // TODO(b/149806065): logger.atSevere().log("Can't start accepting WifiLan - // connections for %s because WifiLan isn't available.", serviceId); - return false; - } - - ScopedPtr> - scoped_wifi_lan_accepted_connection_callback( - new WifiLanAcceptedConnectionCallback( - accepted_connection_callback)); - - // TODO(b/149806065): Implements platform wifi-lan medium. - // A possible implementation is: - // wifi_lan_medium_->StartAcceptingConnections( - // service_id, Ptr( - // wifi_lan_accepted_connection_callback.release())); - - accepting_connections_info_.service_id.assign(service_id.data()); - return false; + NEARBY_LOG(INFO, "Turned off WifiLan discovering with service id=%s", + service_id.c_str()); + bool ret = medium_.StopDiscovery(service_id); + discovering_info_.Clear(); + return ret; } -template -void WifiLan::StopAcceptingConnections(absl::string_view service_id) { - Synchronized s(lock_.get()); +bool WifiLan::IsDiscovering(const std::string& service_id) { + MutexLock lock(&mutex_); - if (!IsAcceptingConnections(service_id)) { - // TODO(b/149806065): logger.atDebug().log("Can't stop accepting WifiLan - // connections because it was never started."); - return; + return IsDiscoveringLocked(service_id); +} + +bool WifiLan::IsDiscoveringLocked(const std::string& service_id) { + return discovering_info_.Existed(service_id); +} + +bool WifiLan::StartAcceptingConnections(const std::string& service_id, + AcceptedConnectionCallback callback) { + MutexLock lock(&mutex_); + + if (service_id.empty()) { + NEARBY_LOG(INFO, + "Refusing to start accepting WifiLan connections with empty " + "service id."); + return false; } - // TODO(b/149806065): Implements platform wifi-lan medium.); - // A possible implementation is: - // wifi_lan_medium_->StopAcceptingConnections( - // accepting_connections_info_.service_id); + if (!IsAvailableLocked()) { + NEARBY_LOG(INFO, + "Can't start accepting WifiLan connections for %s because " + "WifiLan isn't available.", + service_id.c_str()); + return false; + } + if (IsAcceptingConnectionsLocked(service_id)) { + NEARBY_LOG(INFO, + "Refusing to start accepting WifiLan connections for %s because " + "another WifiLan service socket is already in-progress.", + service_id.c_str()); + return false; + } + + if (!medium_.StartAcceptingConnections(service_id, callback)) { + NEARBY_LOG(INFO, "Failed to accept connections callback for %s.", + service_id.c_str()); + return false; + } + + accepting_connections_info_.Add(service_id); + return true; +} + +bool WifiLan::StopAcceptingConnections(const std::string& service_id) { + MutexLock lock(&mutex_); + + if (!IsAcceptingConnectionsLocked(service_id)) { + NEARBY_LOG(INFO, + "Can't stop accepting WifiLan connections because it was never " + "started."); + return false; + } + + bool ret = medium_.StopAcceptingConnections(service_id); // Reset our bundle of accepting connections state to mark that we're no // longer accepting connections. - accepting_connections_info_.service_id.clear(); + accepting_connections_info_.Remove(service_id); + return ret; } -template -bool WifiLan::IsAcceptingConnections(absl::string_view service_id) { - Synchronized s(lock_.get()); +bool WifiLan::IsAcceptingConnections(const std::string& service_id) { + MutexLock lock(&mutex_); - return !accepting_connections_info_.service_id.empty(); + return IsAcceptingConnectionsLocked(service_id); } -template -Ptr WifiLan::Connect( - Ptr wifi_lan_service, absl::string_view service_id) { - Synchronized s(lock_.get()); +bool WifiLan::IsAcceptingConnectionsLocked(const std::string& service_id) { + return accepting_connections_info_.Existed(service_id); +} - if (wifi_lan_service.isNull() || service_id.empty()) { - return Ptr(); +WifiLanSocket WifiLan::Connect(WifiLanService& wifi_lan_service, + const std::string& service_id) { + MutexLock lock(&mutex_); + NEARBY_LOG(INFO, "WifiLan::Connect: service=%p, service_info_name=%s", + &wifi_lan_service, wifi_lan_service.GetServiceName().c_str()); + // Socket to return. To allow for NRVO to work, it has to be a single object. + WifiLanSocket socket; + + if (service_id.empty()) { + NEARBY_LOG(INFO, + "Refusing to create WifiLan socket with empty service_id."); + return socket; } - if (!IsAvailable()) { - return Ptr(); + if (!IsAvailableLocked()) { + NEARBY_LOG(INFO, + "Can't create client WifiLan socket [service_id=%s]; WifiLan " + "isn't available.", + service_id.c_str()); + return socket; } - // TODO(b/149806065): Implements platform wifi-lan medium. - // A possible implementation is: - // return wifi_lan_medium_->Connect(wifi_lan_service, service_id); - return Ptr(); + socket = medium_.Connect(wifi_lan_service, service_id); + if (!socket.IsValid()) { + NEARBY_LOG(INFO, "Failed to Connect via WifiLan [service_id=%s]", + service_id.c_str()); + } + + return socket; +} + +WifiLanService WifiLan::GetRemoteWifiLanService(const std::string& ip_address, + int port) { + MutexLock lock(&mutex_); + return medium_.FindRemoteService(ip_address, port); } -} // namespace mediums } // namespace connections } // namespace nearby } // namespace location diff --git a/cpp/core/internal/mediums/wifi_lan.h b/cpp/core/internal/mediums/wifi_lan.h index 953cbf1f..3029b5a8 100644 --- a/cpp/core/internal/mediums/wifi_lan.h +++ b/cpp/core/internal/mediums/wifi_lan.h @@ -2,159 +2,145 @@ #define CORE_INTERNAL_MEDIUMS_WIFI_LAN_H_ #include +#include -#include "platform/api/lock.h" -#include "platform/api/wifi_lan.h" -#include "platform/byte_array.h" -#include "platform/port/string.h" -#include "platform/ptr.h" -#include "absl/strings/string_view.h" +#include "platform/base/byte_array.h" +#include "platform/public/multi_thread_executor.h" +#include "platform/public/mutex.h" +#include "platform/public/wifi_lan.h" +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" namespace location { namespace nearby { namespace connections { -namespace mediums { -class DiscoveredServiceCallback { - public: - virtual ~DiscoveredServiceCallback() = default; - - virtual void OnServiceDiscovered(Ptr wifi_lan_service) = 0; - virtual void OnServiceLost(Ptr wifi_lan_service) = 0; -}; - -template class WifiLan { public: - WifiLan(); - virtual ~WifiLan() = default; + using DiscoveredServiceCallback = WifiLanMedium::DiscoveredServiceCallback; + using AcceptedConnectionCallback = WifiLanMedium::AcceptedConnectionCallback; - bool IsAvailable(); + // Returns true, if WifiLan communications are supported by a platform. + bool IsAvailable() const ABSL_LOCKS_EXCLUDED(mutex_); - bool StartAdvertising(absl::string_view service_id, - absl::string_view wifi_lan_service_info_name); - void StopAdvertising(absl::string_view service_id); - bool IsAdvertising(); + // Sets custom service info name, endpoint info name and then enables WifiLan + // advertising. + // Returns true, if name is successfully set, and false otherwise. + bool StartAdvertising(const std::string& service_id, + const std::string& service_info_name, + const std::string& endpoint_info_name) + ABSL_LOCKS_EXCLUDED(mutex_); - bool StartDiscovery( - absl::string_view service_id, - Ptr discovered_service_callback); - void StopDiscovery(absl::string_view service_id); - bool IsDiscovering(absl::string_view service_id); + // Disables WifiLan advertising, and restores service info name to + // what they were before the call to StartAdvertising(). + bool StopAdvertising(const std::string& service_id) + ABSL_LOCKS_EXCLUDED(mutex_); - class AcceptedConnectionCallback { - public: - virtual ~AcceptedConnectionCallback() = default; + bool IsAdvertising(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_); - virtual void OnConnectionAccepted(Ptr socket, - absl::string_view service_id) = 0; - }; + // Enables WifiLan discovery mode. Will report any discoverable services in + // range through a callback. Returns true, if discovery mode was enabled, + // false otherwise. + bool StartDiscovery(const std::string& service_id, + DiscoveredServiceCallback callback) + ABSL_LOCKS_EXCLUDED(mutex_); - bool StartAcceptingConnections( - absl::string_view service_id, - Ptr accepted_connection_callback); - void StopAcceptingConnections(absl::string_view service_id); - bool IsAcceptingConnections(absl::string_view service_id); + // Disables WifiLan discovery mode. + bool StopDiscovery(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_); - Ptr Connect(Ptr wifi_lan_service, - absl::string_view service_id); + bool IsDiscovering(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_); + + // Starts a worker thread, creates a WifiLan socket, associates it with a + // service id. + bool StartAcceptingConnections(const std::string& service_id, + AcceptedConnectionCallback callback) + ABSL_LOCKS_EXCLUDED(mutex_); + + // Closes socket corresponding to a service id. + bool StopAcceptingConnections(const std::string& service_id) + ABSL_LOCKS_EXCLUDED(mutex_); + + bool IsAcceptingConnections(const std::string& service_id) + ABSL_LOCKS_EXCLUDED(mutex_); + + // Establishes connection to WifiLan service that was might be started on + // another service with StartAcceptingConnections() using the same service_id. + // Blocks until connection is established, or server-side is terminated. + // Returns socket instance. On success, WifiLanSocket.IsValid() return true. + WifiLanSocket Connect(WifiLanService& wifi_lan_service, + const std::string& service_id) + ABSL_LOCKS_EXCLUDED(mutex_); + + WifiLanService GetRemoteWifiLanService(const std::string& ip_address, + int port) ABSL_LOCKS_EXCLUDED(mutex_); private: - class DiscoveredServiceCallbackBridge - : public WifiLanMedium::DiscoveredServiceCallback { - public: - explicit DiscoveredServiceCallbackBridge( - Ptr discovered_service_callback) - : discovered_service_callback_(discovered_service_callback) {} - ~DiscoveredServiceCallbackBridge() override = default; - - void OnServiceDiscovered(Ptr wifi_lan_service) override { - discovered_service_callback_->OnServiceDiscovered(wifi_lan_service); + struct AdvertisingInfo { + bool Empty() const { return service_ids.empty(); } + void Clear() { service_ids.clear(); } + void Add(const std::string& service_id) { service_ids.emplace(service_id); } + void Remove(const std::string& service_id) { + service_ids.erase(service_id); } - void OnServiceLost(Ptr wifi_lan_service) override { - discovered_service_callback_->OnServiceLost(wifi_lan_service); + bool Existed(const std::string& service_id) const { + return service_ids.contains(service_id); } - private: - ScopedPtr> - discovered_service_callback_; - }; - - class WifiLanAcceptedConnectionCallback - : public WifiLanMedium::AcceptedConnectionCallback { - public: - explicit WifiLanAcceptedConnectionCallback( - Ptr accepted_connection_callback) - : accepted_connection_callback_(accepted_connection_callback) {} - ~WifiLanAcceptedConnectionCallback() override = default; - - void OnConnectionAccepted(Ptr wifi_lan_socket, - absl::string_view service_id) override { - accepted_connection_callback_->OnConnectionAccepted(wifi_lan_socket, - service_id); - } - - private: - ScopedPtr> - accepted_connection_callback_; + absl::flat_hash_set service_ids; }; struct DiscoveringInfo { - DiscoveringInfo() = default; - explicit DiscoveringInfo(absl::string_view service_id) - : service_id(service_id) {} - ~DiscoveringInfo() = default; + bool Empty() const { return service_ids.empty(); } + void Clear() { service_ids.clear(); } + void Add(const std::string& service_id) { service_ids.emplace(service_id); } + void Remove(const std::string& service_id) { + service_ids.erase(service_id); + } + bool Existed(const std::string& service_id) const { + return service_ids.contains(service_id); + } - string service_id; - }; - - struct AdvertisingInfo { - AdvertisingInfo() = default; - explicit AdvertisingInfo(absl::string_view service_id) - : service_id(service_id) {} - ~AdvertisingInfo() = default; - - string service_id; + absl::flat_hash_set service_ids; }; struct AcceptingConnectionsInfo { - AcceptingConnectionsInfo() = default; - explicit AcceptingConnectionsInfo(absl::string_view service_id) - : service_id(service_id) {} - ~AcceptingConnectionsInfo() = default; + bool Empty() const { return service_ids.empty(); } + void Clear() { service_ids.clear(); } + void Add(const std::string& service_id) { service_ids.emplace(service_id); } + void Remove(const std::string& service_id) { + service_ids.erase(service_id); + } + bool Existed(const std::string& service_id) const { + return service_ids.contains(service_id); + } - string service_id; + absl::flat_hash_set service_ids; }; - // ------------ GENERAL ------------ + // Same as IsAvailable(), but must be called with mutex_ held. + bool IsAvailableLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - ScopedPtr> lock_; + // Same as IsAdvertising(), but must be called with mutex_ held. + bool IsAdvertisingLocked(const std::string& service_id) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - // ---------- CORE WIFILAN------------ + // Same as IsDiscovering(), but must be called with mutex_ held. + bool IsDiscoveringLocked(const std::string& service_id) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - // The underlying, per-platform implementation. - ScopedPtr> wifi_lan_medium_; + // Same as IsAcceptingConnections(), but must be called with mutex_ held. + bool IsAcceptingConnectionsLocked(const std::string& service_id) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - // ------------ DISCOVERY ------------ - - // discovering_info_ is not scoped because it's nullable. - DiscoveringInfo discovering_info_; - - // ------------ ADVERTISING ------------ - - // A bundle of state required to start/stop WifiLan service publishing. - AdvertisingInfo advertising_info_; - - // A bundle of state required to start/stop accepting WifiLan service - /// connections. - AcceptingConnectionsInfo accepting_connections_info_; + mutable Mutex mutex_; + WifiLanMedium medium_ ABSL_GUARDED_BY(mutex_); + AdvertisingInfo advertising_info_ ABSL_GUARDED_BY(mutex_); + DiscoveringInfo discovering_info_ ABSL_GUARDED_BY(mutex_); + AcceptingConnectionsInfo accepting_connections_info_ ABSL_GUARDED_BY(mutex_); }; -} // namespace mediums } // namespace connections } // namespace nearby } // namespace location -#include "core/internal/mediums/wifi_lan.cc" - #endif // CORE_INTERNAL_MEDIUMS_WIFI_LAN_H_ diff --git a/cpp/core_v2/internal/mediums/wifi_lan_test.cc b/cpp/core/internal/mediums/wifi_lan_test.cc similarity index 85% rename from cpp/core_v2/internal/mediums/wifi_lan_test.cc rename to cpp/core/internal/mediums/wifi_lan_test.cc index c0586b94..20e75ac1 100644 --- a/cpp/core_v2/internal/mediums/wifi_lan_test.cc +++ b/cpp/core/internal/mediums/wifi_lan_test.cc @@ -1,11 +1,11 @@ -#include "core_v2/internal/mediums/wifi_lan.h" +#include "core/internal/mediums/wifi_lan.h" #include -#include "platform_v2/base/medium_environment.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/logging.h" -#include "platform_v2/public/wifi_lan.h" +#include "platform/base/medium_environment.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/logging.h" +#include "platform/public/wifi_lan.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/strings/string_view.h" @@ -19,6 +19,7 @@ constexpr absl::Duration kWaitDuration = absl::Milliseconds(1000); constexpr absl::string_view kServiceID{"com.google.location.nearby.apps.test"}; constexpr absl::string_view kServiceInfoName{ "Simulated WifiLan service encrypted string #1"}; +constexpr absl::string_view kEndpointName{"Simulated endpoint name"}; class WifiLanTest : public ::testing::Test { protected: @@ -46,6 +47,7 @@ TEST_F(WifiLanTest, CanStartAdvertising) { WifiLan wifi_lan_b; std::string service_id(kServiceID); std::string service_info_name{kServiceInfoName}; + std::string endpoint_info_name{kEndpointName}; CountDownLatch found_latch(1); wifi_lan_b.StartDiscovery( @@ -57,7 +59,8 @@ TEST_F(WifiLanTest, CanStartAdvertising) { }, }); - EXPECT_TRUE(wifi_lan_a.StartAdvertising(service_id, service_info_name)); + EXPECT_TRUE(wifi_lan_a.StartAdvertising(service_id, service_info_name, + endpoint_info_name)); EXPECT_TRUE(found_latch.Await(kWaitDuration).result()); EXPECT_TRUE(wifi_lan_a.StopAdvertising(service_id)); EXPECT_TRUE(wifi_lan_b.StopDiscovery(service_id)); @@ -70,10 +73,12 @@ TEST_F(WifiLanTest, CanStartDiscovery) { WifiLan wifi_lan_b; std::string service_id(kServiceID); std::string service_info_name{kServiceInfoName}; + std::string endpoint_info_name{kEndpointName}; CountDownLatch accept_latch(1); CountDownLatch lost_latch(1); - wifi_lan_b.StartAdvertising(service_id, service_info_name); + wifi_lan_b.StartAdvertising(service_id, service_info_name, + endpoint_info_name); EXPECT_TRUE(wifi_lan_a.StartDiscovery( service_id, { @@ -101,10 +106,12 @@ TEST_F(WifiLanTest, CanStartAcceptingConnectionsAndConnect) { WifiLan wifi_lan_b; std::string service_id(kServiceID); std::string service_info_name{kServiceInfoName}; + std::string endpoint_info_name{kEndpointName}; CountDownLatch found_latch(1); CountDownLatch accept_latch(1); - wifi_lan_a.StartAdvertising(service_id, service_info_name); + wifi_lan_a.StartAdvertising(service_id, service_info_name, + endpoint_info_name); wifi_lan_a.StartAcceptingConnections( service_id, { diff --git a/cpp/core_v2/internal/mock_service_controller.h b/cpp/core/internal/mock_service_controller.h similarity index 85% rename from cpp/core_v2/internal/mock_service_controller.h rename to cpp/core/internal/mock_service_controller.h index d6029bbd..d89e47e1 100644 --- a/cpp/core_v2/internal/mock_service_controller.h +++ b/cpp/core/internal/mock_service_controller.h @@ -1,7 +1,7 @@ -#ifndef CORE_V2_INTERNAL_MOCK_SERVICE_CONTROLLER_H_ -#define CORE_V2_INTERNAL_MOCK_SERVICE_CONTROLLER_H_ +#ifndef CORE_INTERNAL_MOCK_SERVICE_CONTROLLER_H_ +#define CORE_INTERNAL_MOCK_SERVICE_CONTROLLER_H_ -#include "core_v2/internal/service_controller.h" +#include "core/internal/service_controller.h" #include "gmock/gmock.h" namespace location { @@ -33,6 +33,11 @@ class MockServiceController : public ServiceController { MOCK_METHOD(void, StopDiscovery, (ClientProxy * client), (override)); + MOCK_METHOD(void, InjectEndpoint, + (ClientProxy * client, const std::string& service_id, + const OutOfBandConnectionMetadata& metadata), + (override)); + MOCK_METHOD(Status, RequestConnection, (ClientProxy * client, const std::string& endpoint_id, const ConnectionRequestInfo& info, @@ -69,4 +74,4 @@ class MockServiceController : public ServiceController { } // namespace nearby } // namespace location -#endif // CORE_V2_INTERNAL_MOCK_SERVICE_CONTROLLER_H_ +#endif // CORE_INTERNAL_MOCK_SERVICE_CONTROLLER_H_ diff --git a/cpp/core/internal/offline_frames.cc b/cpp/core/internal/offline_frames.cc index d077205d..5e5d2452 100644 --- a/cpp/core/internal/offline_frames.cc +++ b/cpp/core/internal/offline_frames.cc @@ -3,255 +3,388 @@ #include #include -#include "platform/byte_array.h" +#include "core/internal/message_lite.h" +#include "core/status.h" +#include "proto/connections/offline_wire_formats.pb.h" +#include "platform/base/byte_array.h" namespace location { namespace nearby { namespace connections { - -using ExceptionOrOfflineFrame = ExceptionOr>; - +namespace parser { namespace { -std::unique_ptr NewOfflineFrame( - V1Frame::FrameType frame_type, - std::unique_ptr message) { - V1Frame *v1_frame = new V1Frame(); - v1_frame->set_type(frame_type); - switch (frame_type) { - case V1Frame::CONNECTION_REQUEST: - v1_frame->set_allocated_connection_request( - static_cast(message.release())); - break; - case V1Frame::CONNECTION_RESPONSE: - v1_frame->set_allocated_connection_response( - static_cast(message.release())); - break; - case V1Frame::PAYLOAD_TRANSFER: - v1_frame->set_allocated_payload_transfer( - static_cast(message.release())); - break; - case V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION: - v1_frame->set_allocated_bandwidth_upgrade_negotiation( - static_cast(message.release())); - break; - case V1Frame::KEEP_ALIVE: - v1_frame->set_allocated_keep_alive( - static_cast(message.release())); - break; - default: - break; - } +using ExceptionOrOfflineFrame = ExceptionOr; +using MessageLite = ::google::protobuf::MessageLite; - auto offline_frame = std::make_unique(); - offline_frame->set_version(OfflineFrame::V1); - offline_frame->set_allocated_v1(v1_frame); - return offline_frame; -} - -ConstPtr toBytes(std::unique_ptr offline_frame) { - auto *bytes = new ByteArray{offline_frame->ByteSizeLong()}; - offline_frame->SerializeToArray(bytes->getData(), bytes->size()); - return MakeConstPtr(bytes); +ByteArray ToBytes(OfflineFrame&& frame) { + ByteArray bytes(frame.ByteSizeLong()); + frame.set_version(OfflineFrame::V1); + frame.SerializeToArray(bytes.data(), bytes.size()); + return bytes; } } // namespace -ExceptionOrOfflineFrame OfflineFrames::fromBytes( - ConstPtr offline_frame_bytes) { - auto offline_frame = std::make_unique(); +ExceptionOrOfflineFrame FromBytes(const ByteArray& bytes) { + OfflineFrame frame; - if (!offline_frame->ParseFromArray(offline_frame_bytes->getData(), - offline_frame_bytes->size())) { - return ExceptionOrOfflineFrame(Exception::INVALID_PROTOCOL_BUFFER); + if (frame.ParseFromString(std::string(bytes))) { + return ExceptionOrOfflineFrame(std::move(frame)); + } else { + return ExceptionOrOfflineFrame(Exception::kInvalidProtocolBuffer); } - - return ExceptionOrOfflineFrame(MakeConstPtr(offline_frame.release())); } -V1Frame::FrameType OfflineFrames::getFrameType( - ConstPtr offline_frame) { - if ((offline_frame->version() == OfflineFrame::V1) && - offline_frame->has_v1()) { - return offline_frame->v1().type(); +V1Frame::FrameType GetFrameType(const OfflineFrame& frame) { + if ((frame.version() == OfflineFrame::V1) && frame.has_v1()) { + return frame.v1().type(); } return V1Frame::UNKNOWN_FRAME_TYPE; } -// TODO(b/155752436): Use byte array endpoint_info instead of endpoint_name. -ConstPtr OfflineFrames::forConnectionRequest( - const std::string &endpoint_id, const std::string &endpoint_name, - std::int32_t nonce, - const std::vector &mediums) { - auto connection_request = std::make_unique(); - connection_request->set_endpoint_id(endpoint_id); - connection_request->set_endpoint_name(endpoint_name); - connection_request->set_endpoint_info(endpoint_name); - connection_request->set_nonce(nonce); +ByteArray ForConnectionRequest(const std::string& endpoint_id, + const ByteArray& endpoint_info, + std::int32_t nonce, + const std::vector& mediums) { + OfflineFrame frame; - for (std::vector::const_iterator it = - mediums.begin(); - it != mediums.end(); it++) { - connection_request->add_mediums(mediumToConnectionRequestMedium(*it)); + frame.set_version(OfflineFrame::V1); + auto* v1_frame = frame.mutable_v1(); + v1_frame->set_type(V1Frame::CONNECTION_REQUEST); + auto* connection_request = v1_frame->mutable_connection_request(); + connection_request->set_endpoint_id(endpoint_id); + connection_request->set_endpoint_name(std::string(endpoint_info)); + connection_request->set_endpoint_info(std::string(endpoint_info)); + connection_request->set_nonce(nonce); + for (const auto& medium : mediums) { + connection_request->add_mediums(MediumToConnectionRequestMedium(medium)); } - return toBytes(NewOfflineFrame(V1Frame::CONNECTION_REQUEST, - std::move(connection_request))); + return ToBytes(std::move(frame)); } -ConstPtr OfflineFrames::forConnectionResponse(std::int32_t status) { - auto connection_response = std::make_unique(); - connection_response->set_status(status); +ByteArray ForConnectionResponse(std::int32_t status) { + OfflineFrame frame; - return toBytes(NewOfflineFrame(V1Frame::CONNECTION_RESPONSE, - std::move(connection_response))); + frame.set_version(OfflineFrame::V1); + auto* v1_frame = frame.mutable_v1(); + v1_frame->set_type(V1Frame::CONNECTION_RESPONSE); + auto* sub_frame = v1_frame->mutable_connection_response(); + + // For backward compatiblility, here still sets both status and response + // parameters until the response feature is roll out in all supported + // devices. + sub_frame->set_status(status); + sub_frame->set_response(status == Status::kSuccess + ? ConnectionResponseFrame::ACCEPT + : ConnectionResponseFrame::REJECT); + + return ToBytes(std::move(frame)); } -ConstPtr OfflineFrames::forDataPayloadTransferFrame( - const PayloadTransferFrame::PayloadHeader &header, - const PayloadTransferFrame::PayloadChunk &chunk) { - auto payload_transfer = std::make_unique(); - payload_transfer->set_packet_type(PayloadTransferFrame::DATA); - *payload_transfer->mutable_payload_header() = header; - *payload_transfer->mutable_payload_chunk() = chunk; +ByteArray ForDataPayloadTransfer( + const PayloadTransferFrame::PayloadHeader& header, + const PayloadTransferFrame::PayloadChunk& chunk) { + OfflineFrame frame; - return toBytes( - NewOfflineFrame(V1Frame::PAYLOAD_TRANSFER, std::move(payload_transfer))); + frame.set_version(OfflineFrame::V1); + auto* v1_frame = frame.mutable_v1(); + v1_frame->set_type(V1Frame::PAYLOAD_TRANSFER); + auto* sub_frame = v1_frame->mutable_payload_transfer(); + sub_frame->set_packet_type(PayloadTransferFrame::DATA); + *sub_frame->mutable_payload_header() = header; + *sub_frame->mutable_payload_chunk() = chunk; + + return ToBytes(std::move(frame)); } -ConstPtr OfflineFrames::forControlPayloadTransferFrame( - const PayloadTransferFrame::PayloadHeader &header, - const PayloadTransferFrame::ControlMessage &control) { - auto payload_transfer = std::make_unique(); - payload_transfer->set_packet_type(PayloadTransferFrame::CONTROL); - *payload_transfer->mutable_payload_header() = header; - *payload_transfer->mutable_control_message() = control; +ByteArray ForControlPayloadTransfer( + const PayloadTransferFrame::PayloadHeader& header, + const PayloadTransferFrame::ControlMessage& control) { + OfflineFrame frame; - return toBytes( - NewOfflineFrame(V1Frame::PAYLOAD_TRANSFER, std::move(payload_transfer))); + frame.set_version(OfflineFrame::V1); + auto* v1_frame = frame.mutable_v1(); + v1_frame->set_type(V1Frame::PAYLOAD_TRANSFER); + auto* sub_frame = v1_frame->mutable_payload_transfer(); + sub_frame->set_packet_type(PayloadTransferFrame::CONTROL); + *sub_frame->mutable_payload_header() = header; + *sub_frame->mutable_control_message() = control; + + return ToBytes(std::move(frame)); } -ConstPtr OfflineFrames:: - forWifiHotspotUpgradePathAvailableBandwidthUpgradeNegotiationEvent( - const std::string &ssid, const std::string &password, - std::int32_t port) { - auto *wifi_hotspot_credentials = new BandwidthUpgradeNegotiationFrame:: - UpgradePathInfo::WifiHotspotCredentials(); +ByteArray ForBwuWifiHotspotPathAvailable(const std::string& ssid, + const std::string& password, + std::int32_t port) { + OfflineFrame frame; + + frame.set_version(OfflineFrame::V1); + auto* v1_frame = frame.mutable_v1(); + v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); + auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); + sub_frame->set_event_type( + BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE); + auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info(); + upgrade_path_info->set_medium(UpgradePathInfo::WIFI_HOTSPOT); + auto* wifi_hotspot_credentials = + upgrade_path_info->mutable_wifi_hotspot_credentials(); wifi_hotspot_credentials->set_ssid(ssid); wifi_hotspot_credentials->set_password(password); wifi_hotspot_credentials->set_port(port); - auto *upgrade_path_info = - new BandwidthUpgradeNegotiationFrame::UpgradePathInfo(); - upgrade_path_info->set_medium( - BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WIFI_HOTSPOT); - upgrade_path_info->set_allocated_wifi_hotspot_credentials( - wifi_hotspot_credentials); - - auto bandwidth_upgrade_negotiation = - std::make_unique(); - bandwidth_upgrade_negotiation->set_event_type( - BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE); - bandwidth_upgrade_negotiation->set_allocated_upgrade_path_info( - upgrade_path_info); - - return toBytes(NewOfflineFrame(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION, - std::move(bandwidth_upgrade_negotiation))); + return ToBytes(std::move(frame)); } -ConstPtr -OfflineFrames::forLastWriteToPriorChannelBandwidthUpgradeNegotiationEvent() { - auto bandwidth_upgrade_negotiation = - std::make_unique(); - bandwidth_upgrade_negotiation->set_event_type( +ByteArray ForBwuWifiLanPathAvailable(const std::string& ip_address, + std::int32_t port) { + OfflineFrame frame; + + frame.set_version(OfflineFrame::V1); + auto* v1_frame = frame.mutable_v1(); + v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); + auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); + sub_frame->set_event_type( + BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE); + auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info(); + upgrade_path_info->set_medium(UpgradePathInfo::WIFI_LAN); + auto* wifi_lan_socket = upgrade_path_info->mutable_wifi_lan_socket(); + wifi_lan_socket->set_ip_address(ip_address); + wifi_lan_socket->set_wifi_port(port); + + return ToBytes(std::move(frame)); +} + +ByteArray ForBwuBluetoothPathAvailable(const std::string& service_id, + const std::string& mac_address) { + OfflineFrame frame; + + frame.set_version(OfflineFrame::V1); + auto* v1_frame = frame.mutable_v1(); + v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); + auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); + sub_frame->set_event_type( + BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE); + auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info(); + upgrade_path_info->set_medium(UpgradePathInfo::BLUETOOTH); + auto* bluetooth_credentials = + upgrade_path_info->mutable_bluetooth_credentials(); + bluetooth_credentials->set_mac_address(mac_address); + bluetooth_credentials->set_service_name(service_id); + + return ToBytes(std::move(frame)); +} + +ByteArray ForBwuWebrtcPathAvailable(const std::string& peer_id, + const LocationHint& location_hint) { + OfflineFrame frame; + + frame.set_version(OfflineFrame::V1); + auto* v1_frame = frame.mutable_v1(); + v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); + auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); + sub_frame->set_event_type( + BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE); + auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info(); + upgrade_path_info->set_medium(UpgradePathInfo::WEB_RTC); + auto* webrtc_credentials = upgrade_path_info->mutable_web_rtc_credentials(); + webrtc_credentials->set_peer_id(peer_id); + auto* local_location_hint = webrtc_credentials->mutable_location_hint(); + *local_location_hint = location_hint; + + return ToBytes(std::move(frame)); +} + +ByteArray ForBwuLastWrite() { + OfflineFrame frame; + + frame.set_version(OfflineFrame::V1); + auto* v1_frame = frame.mutable_v1(); + v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); + auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); + sub_frame->set_event_type( BandwidthUpgradeNegotiationFrame::LAST_WRITE_TO_PRIOR_CHANNEL); - return toBytes(NewOfflineFrame(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION, - std::move(bandwidth_upgrade_negotiation))); + return ToBytes(std::move(frame)); } -ConstPtr -OfflineFrames::forSafeToClosePriorChannelBandwidthUpgradeNegotiationEvent() { - auto bandwidth_upgrade_negotiation = - std::make_unique(); - bandwidth_upgrade_negotiation->set_event_type( +ByteArray ForBwuSafeToClose() { + OfflineFrame frame; + + frame.set_version(OfflineFrame::V1); + auto* v1_frame = frame.mutable_v1(); + v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); + auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); + sub_frame->set_event_type( BandwidthUpgradeNegotiationFrame::SAFE_TO_CLOSE_PRIOR_CHANNEL); - return toBytes(NewOfflineFrame(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION, - std::move(bandwidth_upgrade_negotiation))); + return ToBytes(std::move(frame)); } -ConstPtr -OfflineFrames::forClientIntroductionBandwidthUpgradeNegotiationEvent( - const std::string &endpoint_id) { - auto *client_introduction = - new BandwidthUpgradeNegotiationFrame::ClientIntroduction(); +ByteArray ForBwuIntroduction(const std::string& endpoint_id) { + OfflineFrame frame; + + frame.set_version(OfflineFrame::V1); + auto* v1_frame = frame.mutable_v1(); + v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); + auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); + sub_frame->set_event_type( + BandwidthUpgradeNegotiationFrame::CLIENT_INTRODUCTION); + auto* client_introduction = sub_frame->mutable_client_introduction(); client_introduction->set_endpoint_id(endpoint_id); - auto bandwidth_upgrade_negotiation = - std::make_unique(); - bandwidth_upgrade_negotiation->set_event_type( - BandwidthUpgradeNegotiationFrame::CLIENT_INTRODUCTION); - bandwidth_upgrade_negotiation->set_allocated_client_introduction( - client_introduction); - - return toBytes(NewOfflineFrame(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION, - std::move(bandwidth_upgrade_negotiation))); + return ToBytes(std::move(frame)); } -ConstPtr OfflineFrames::forKeepAlive() { - return toBytes( - NewOfflineFrame(V1Frame::KEEP_ALIVE, std::make_unique())); +ByteArray ForBwuFailure(const UpgradePathInfo& info) { + OfflineFrame frame; + + frame.set_version(OfflineFrame::V1); + auto* v1_frame = frame.mutable_v1(); + v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); + auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); + sub_frame->set_event_type(BandwidthUpgradeNegotiationFrame::UPGRADE_FAILURE); + auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info(); + *upgrade_path_info = info; + + return ToBytes(std::move(frame)); } -ConnectionRequestFrame::Medium OfflineFrames::mediumToConnectionRequestMedium( - proto::connections::Medium medium) { +ByteArray ForKeepAlive() { + OfflineFrame frame; + + frame.set_version(OfflineFrame::V1); + auto* v1_frame = frame.mutable_v1(); + v1_frame->set_type(V1Frame::KEEP_ALIVE); + v1_frame->mutable_keep_alive(); + + return ToBytes(std::move(frame)); +} + +ByteArray ForDisconnection() { + OfflineFrame frame; + + frame.set_version(OfflineFrame::V1); + auto* v1_frame = frame.mutable_v1(); + v1_frame->set_type(V1Frame::DISCONNECTION); + v1_frame->mutable_disconnection(); + + return ToBytes(std::move(frame)); +} + +UpgradePathInfo::Medium MediumToUpgradePathInfoMedium(Medium medium) { switch (medium) { - case proto::connections::MDNS: + case Medium::MDNS: + return UpgradePathInfo::MDNS; + case Medium::BLUETOOTH: + return UpgradePathInfo::BLUETOOTH; + case Medium::WIFI_HOTSPOT: + return UpgradePathInfo::WIFI_HOTSPOT; + case Medium::BLE: + return UpgradePathInfo::BLE; + case Medium::WIFI_LAN: + return UpgradePathInfo::WIFI_LAN; + case Medium::WIFI_AWARE: + return UpgradePathInfo::WIFI_AWARE; + case Medium::NFC: + return UpgradePathInfo::NFC; + case Medium::WIFI_DIRECT: + return UpgradePathInfo::WIFI_DIRECT; + case Medium::WEB_RTC: + return UpgradePathInfo::WEB_RTC; + default: + return UpgradePathInfo::UNKNOWN_MEDIUM; + } +} + +Medium UpgradePathInfoMediumToMedium(UpgradePathInfo::Medium medium) { + switch (medium) { + case UpgradePathInfo::MDNS: + return Medium::MDNS; + case UpgradePathInfo::BLUETOOTH: + return Medium::BLUETOOTH; + case UpgradePathInfo::WIFI_HOTSPOT: + return Medium::WIFI_HOTSPOT; + case UpgradePathInfo::BLE: + return Medium::BLE; + case UpgradePathInfo::WIFI_LAN: + return Medium::WIFI_LAN; + case UpgradePathInfo::WIFI_AWARE: + return Medium::WIFI_AWARE; + case UpgradePathInfo::NFC: + return Medium::NFC; + case UpgradePathInfo::WIFI_DIRECT: + return Medium::WIFI_DIRECT; + case UpgradePathInfo::WEB_RTC: + return Medium::WEB_RTC; + default: + return Medium::UNKNOWN_MEDIUM; + } +} + +ConnectionRequestFrame::Medium MediumToConnectionRequestMedium(Medium medium) { + switch (medium) { + case Medium::MDNS: return ConnectionRequestFrame::MDNS; - case proto::connections::BLUETOOTH: + case Medium::BLUETOOTH: return ConnectionRequestFrame::BLUETOOTH; - case proto::connections::WIFI_HOTSPOT: + case Medium::WIFI_HOTSPOT: return ConnectionRequestFrame::WIFI_HOTSPOT; - case proto::connections::BLE: + case Medium::BLE: return ConnectionRequestFrame::BLE; - case proto::connections::WIFI_LAN: + case Medium::WIFI_LAN: return ConnectionRequestFrame::WIFI_LAN; + case Medium::WIFI_AWARE: + return ConnectionRequestFrame::WIFI_AWARE; + case Medium::NFC: + return ConnectionRequestFrame::NFC; + case Medium::WIFI_DIRECT: + return ConnectionRequestFrame::WIFI_DIRECT; + case Medium::WEB_RTC: + return ConnectionRequestFrame::WEB_RTC; default: return ConnectionRequestFrame::UNKNOWN_MEDIUM; } } -proto::connections::Medium OfflineFrames::connectionRequestMediumToMedium( - ConnectionRequestFrame::Medium medium) { +Medium ConnectionRequestMediumToMedium(ConnectionRequestFrame::Medium medium) { switch (medium) { case ConnectionRequestFrame::MDNS: - return proto::connections::Medium::MDNS; + return Medium::MDNS; case ConnectionRequestFrame::BLUETOOTH: - return proto::connections::Medium::BLUETOOTH; + return Medium::BLUETOOTH; case ConnectionRequestFrame::WIFI_HOTSPOT: - return proto::connections::Medium::WIFI_HOTSPOT; + return Medium::WIFI_HOTSPOT; case ConnectionRequestFrame::BLE: - return proto::connections::Medium::BLE; + return Medium::BLE; case ConnectionRequestFrame::WIFI_LAN: - return proto::connections::Medium::WIFI_LAN; + return Medium::WIFI_LAN; + case ConnectionRequestFrame::WIFI_AWARE: + return Medium::WIFI_AWARE; + case ConnectionRequestFrame::NFC: + return Medium::NFC; + case ConnectionRequestFrame::WIFI_DIRECT: + return Medium::WIFI_DIRECT; + case ConnectionRequestFrame::WEB_RTC: + return Medium::WEB_RTC; default: - return proto::connections::Medium::UNKNOWN_MEDIUM; + return Medium::UNKNOWN_MEDIUM; } } -std::vector -OfflineFrames::connectionRequestMediumsToMediums( - const ConnectionRequestFrame &connection_request_frame) { - std::vector result; - for (size_t i = 0; i < connection_request_frame.mediums_size(); i++) { - result.push_back( - connectionRequestMediumToMedium(connection_request_frame.mediums(i))); +std::vector ConnectionRequestMediumsToMediums( + const ConnectionRequestFrame& frame) { + std::vector result; + for (const auto& int_medium : frame.mediums()) { + result.push_back(ConnectionRequestMediumToMedium( + static_cast(int_medium))); } return result; } +} // namespace parser } // namespace connections } // namespace nearby } // namespace location diff --git a/cpp/core/internal/offline_frames.h b/cpp/core/internal/offline_frames.h index 425bac06..f5bdc01c 100644 --- a/cpp/core/internal/offline_frames.h +++ b/cpp/core/internal/offline_frames.h @@ -4,65 +4,71 @@ #include #include +#include "core/options.h" #include "proto/connections/offline_wire_formats.pb.h" -#include "platform/byte_array.h" -#include "platform/exception.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "platform/base/byte_array.h" +#include "platform/base/exception.h" #include "proto/connections_enums.pb.h" -// Detects the right usage. -#include "google/protobuf/message_lite.h" -#define proto_ns google3_proto_compat - - namespace location { namespace nearby { namespace connections { +namespace parser { -class OfflineFrames { - public: - static ExceptionOr > fromBytes( - ConstPtr - offline_frame_bytes); // throws Exception::INVALID_PROTOCOL_BUFFER +using UpgradePathInfo = BandwidthUpgradeNegotiationFrame::UpgradePathInfo; - static V1Frame::FrameType getFrameType(ConstPtr offline_frame); +// Serialize/Deserialize Nearby Connections Protocol messages. - static ConstPtr forConnectionRequest( - const std::string& endpoint_id, const std::string& endpoint_name, - std::int32_t nonce, - const std::vector& mediums); - static ConstPtr forConnectionResponse(std::int32_t status); +// Parses incoming message. +// Returns OfflineFrame if parser was able to understand it, or +// Exception::kInvalidProtocolBuffer, if parser failed. +ExceptionOr FromBytes(const ByteArray& offline_frame_bytes); - static ConstPtr forDataPayloadTransferFrame( - const PayloadTransferFrame::PayloadHeader& header, - const PayloadTransferFrame::PayloadChunk& chunk); - static ConstPtr forControlPayloadTransferFrame( - const PayloadTransferFrame::PayloadHeader& header, - const PayloadTransferFrame::ControlMessage& control); +// Returns FrameType of a parsed message, or +// V1Frame::UNKNOWN_FRAME_TYPE, if frame contents is not recognized. +V1Frame::FrameType GetFrameType(const OfflineFrame& offline_frame); - static ConstPtr - forWifiHotspotUpgradePathAvailableBandwidthUpgradeNegotiationEvent( - const std::string& ssid, const std::string& password, std::int32_t port); - static ConstPtr - forLastWriteToPriorChannelBandwidthUpgradeNegotiationEvent(); - static ConstPtr - forSafeToClosePriorChannelBandwidthUpgradeNegotiationEvent(); - static ConstPtr - forClientIntroductionBandwidthUpgradeNegotiationEvent( - const std::string& endpoint_id); +// Builds Connection Request / Response messages. +ByteArray ForConnectionRequest(const std::string& endpoint_id, + const ByteArray& endpoint_info, + std::int32_t nonce, + const std::vector& mediums); +ByteArray ForConnectionResponse(std::int32_t status); - static ConstPtr forKeepAlive(); +// Builds Payload transfer messages. +ByteArray ForDataPayloadTransfer( + const PayloadTransferFrame::PayloadHeader& header, + const PayloadTransferFrame::PayloadChunk& chunk); +ByteArray ForControlPayloadTransfer( + const PayloadTransferFrame::PayloadHeader& header, + const PayloadTransferFrame::ControlMessage& control); - static ConnectionRequestFrame::Medium mediumToConnectionRequestMedium( - proto::connections::Medium medium); - static proto::connections::Medium connectionRequestMediumToMedium( - ConnectionRequestFrame::Medium medium); - static std::vector - connectionRequestMediumsToMediums( - const ConnectionRequestFrame& connection_request_frame); -}; +// Builds Bandwidth Upgrade [BWU] messages. +ByteArray ForBwuIntroduction(const std::string& endpoint_id); +ByteArray ForBwuWifiHotspotPathAvailable(const std::string& ssid, + const std::string& password, + std::int32_t port); +ByteArray ForBwuWifiLanPathAvailable(const std::string& ip_address, + std::int32_t port); +ByteArray ForBwuBluetoothPathAvailable(const std::string& service_id, + const std::string& mac_address); +ByteArray ForBwuWebrtcPathAvailable(const std::string& peer_id, + const LocationHint& location_hint_a); +ByteArray ForBwuFailure(const UpgradePathInfo& info); +ByteArray ForBwuLastWrite(); +ByteArray ForBwuSafeToClose(); +ByteArray ForKeepAlive(); + +UpgradePathInfo::Medium MediumToUpgradePathInfoMedium(Medium medium); +Medium UpgradePathInfoMediumToMedium(UpgradePathInfo::Medium medium); + +ConnectionRequestFrame::Medium MediumToConnectionRequestMedium(Medium medium); +Medium ConnectionRequestMediumToMedium(ConnectionRequestFrame::Medium medium); +std::vector ConnectionRequestMediumsToMediums( + const ConnectionRequestFrame& connection_request_frame); + +} // namespace parser } // namespace connections } // namespace nearby } // namespace location diff --git a/cpp/core/internal/offline_frames_test.cc b/cpp/core/internal/offline_frames_test.cc index 66460a1b..28cf3190 100644 --- a/cpp/core/internal/offline_frames_test.cc +++ b/cpp/core/internal/offline_frames_test.cc @@ -1,88 +1,301 @@ #include "core/internal/offline_frames.h" +#include #include +#include +#include #include "proto/connections/offline_wire_formats.pb.h" -#include "platform/byte_array.h" +#include "platform/base/byte_array.h" #include "gmock/gmock.h" #include "gtest/gtest.h" -namespace location::nearby::connections { - +namespace location { +namespace nearby { +namespace connections { +namespace parser { namespace { + using Medium = proto::connections::Medium; +using ::testing::EqualsProto; -std::unique_ptr MakeFrame(V1Frame* sub_frame) { - auto frame = std::make_unique(); - frame->set_version(OfflineFrame::V1); - frame->set_allocated_v1(sub_frame); - return frame; -} +constexpr absl::string_view kEndpointId{"ABC"}; +constexpr absl::string_view kEndpointName{"XYZ"}; +constexpr int kNonce = 1234; +constexpr std::array kMediums = { + Medium::MDNS, Medium::BLUETOOTH, Medium::WIFI_HOTSPOT, + Medium::BLE, Medium::WIFI_LAN, Medium::WIFI_AWARE, + Medium::NFC, Medium::WIFI_DIRECT, Medium::WEB_RTC, +}; -void SetSubframe(V1Frame* frame, ConnectionRequestFrame* sub_frame) { - frame->set_type(V1Frame::CONNECTION_REQUEST); - frame->set_allocated_connection_request(sub_frame); -} +TEST(OfflineFramesTest, CanParseMessageFromBytes) { + OfflineFrame tx_message; -constexpr ConnectionRequestFrame::Medium ToConnectionRequestMedium( - proto::connections::Medium medium) { - switch (medium) { - case proto::connections::MDNS: - return ConnectionRequestFrame::MDNS; - case proto::connections::BLUETOOTH: - return ConnectionRequestFrame::BLUETOOTH; - case proto::connections::WIFI_HOTSPOT: - return ConnectionRequestFrame::WIFI_HOTSPOT; - case proto::connections::BLE: - return ConnectionRequestFrame::BLE; - case proto::connections::WIFI_LAN: - return ConnectionRequestFrame::WIFI_LAN; - default: - return ConnectionRequestFrame::UNKNOWN_MEDIUM; + { + tx_message.set_version(OfflineFrame::V1); + auto* v1_frame = tx_message.mutable_v1(); + auto* sub_frame = v1_frame->mutable_connection_request(); + + v1_frame->set_type(V1Frame::CONNECTION_REQUEST); + sub_frame->set_endpoint_id(kEndpointId); + sub_frame->set_endpoint_name(kEndpointName); + sub_frame->set_endpoint_info(kEndpointName); + sub_frame->set_nonce(kNonce); + for (auto& medium : kMediums) { + sub_frame->add_mediums(MediumToConnectionRequestMedium(medium)); + } } + auto serialized_bytes = ByteArray(tx_message.SerializeAsString()); + auto ret_value = FromBytes(serialized_bytes); + ASSERT_TRUE(ret_value.ok()); + const auto& rx_message = ret_value.result(); + EXPECT_THAT(rx_message, EqualsProto(tx_message)); + EXPECT_EQ(GetFrameType(rx_message), V1Frame::CONNECTION_REQUEST); + EXPECT_EQ( + ConnectionRequestMediumsToMediums(rx_message.v1().connection_request()), + std::vector(kMediums.begin(), kMediums.end())); +} + +TEST(OfflineFramesTest, CanGenerateConnectionRequest) { + constexpr char kExpected[] = + R"pb( + version: V1 + v1: < + type: CONNECTION_REQUEST + connection_request: < + endpoint_id: "ABC" + endpoint_name: "XYZ" + endpoint_info: "XYZ" + nonce: 1234 + mediums: MDNS + mediums: BLUETOOTH + mediums: WIFI_HOTSPOT + mediums: BLE + mediums: WIFI_LAN + mediums: WIFI_AWARE + mediums: NFC + mediums: WIFI_DIRECT + mediums: WEB_RTC + > + >)pb"; + ByteArray bytes = ForConnectionRequest( + std::string(kEndpointId), ByteArray{std::string(kEndpointName)}, kNonce, + std::vector(kMediums.begin(), kMediums.end())); + auto response = FromBytes(bytes); + ASSERT_TRUE(response.ok()); + OfflineFrame message = FromBytes(bytes).result(); + EXPECT_THAT(message, EqualsProto(kExpected)); +} + +TEST(OfflineFramesTest, CanGenerateConnectionResponse) { + constexpr char kExpected[] = + R"pb( + version: V1 + v1: < + type: CONNECTION_RESPONSE + connection_response: < + status: 1 + response: REJECT + > + >)pb"; + ByteArray bytes = ForConnectionResponse(1); + auto response = FromBytes(bytes); + ASSERT_TRUE(response.ok()); + OfflineFrame message = FromBytes(bytes).result(); + EXPECT_THAT(message, EqualsProto(kExpected)); +} + +TEST(OfflineFramesTest, CanGenerateControlPayloadTransfer) { + PayloadTransferFrame::PayloadHeader header; + PayloadTransferFrame::ControlMessage control; + header.set_id(12345); + header.set_type(PayloadTransferFrame::PayloadHeader::BYTES); + header.set_total_size(1024); + control.set_event(PayloadTransferFrame::ControlMessage::PAYLOAD_CANCELED); + control.set_offset(150); + + constexpr char kExpected[] = + R"pb( + version: V1 + v1: < + type: PAYLOAD_TRANSFER + payload_transfer: < + packet_type: CONTROL, + payload_header: < type: BYTES id: 12345 total_size: 1024 > + control_message: < event: PAYLOAD_CANCELED offset: 150 > + > + >)pb"; + ByteArray bytes = ForControlPayloadTransfer(header, control); + auto response = FromBytes(bytes); + ASSERT_TRUE(response.ok()); + OfflineFrame message = FromBytes(bytes).result(); + EXPECT_THAT(message, EqualsProto(kExpected)); +} + +TEST(OfflineFramesTest, CanGenerateDataPayloadTransfer) { + PayloadTransferFrame::PayloadHeader header; + PayloadTransferFrame::PayloadChunk chunk; + header.set_id(12345); + header.set_type(PayloadTransferFrame::PayloadHeader::BYTES); + header.set_total_size(1024); + chunk.set_body("payload data"); + chunk.set_offset(150); + chunk.set_flags(1); + + constexpr char kExpected[] = + R"pb( + version: V1 + v1: < + type: PAYLOAD_TRANSFER + payload_transfer: < + packet_type: DATA, + payload_header: < type: BYTES id: 12345 total_size: 1024 > + payload_chunk: < flags: 1 offset: 150 body: "payload data" > + > + >)pb"; + ByteArray bytes = ForDataPayloadTransfer(header, chunk); + auto response = FromBytes(bytes); + ASSERT_TRUE(response.ok()); + OfflineFrame message = FromBytes(bytes).result(); + EXPECT_THAT(message, EqualsProto(kExpected)); +} + +TEST(OfflineFramesTest, CanGenerateBwuWifiHotspotPathAvailable) { + constexpr char kExpected[] = + R"pb( + version: V1 + v1: < + type: BANDWIDTH_UPGRADE_NEGOTIATION + bandwidth_upgrade_negotiation: < + event_type: UPGRADE_PATH_AVAILABLE + upgrade_path_info: < + medium: WIFI_HOTSPOT + wifi_hotspot_credentials: < + ssid: "ssid" + password: "password" + port: 1234 + > + > + > + >)pb"; + ByteArray bytes = ForBwuWifiHotspotPathAvailable("ssid", "password", 1234); + auto response = FromBytes(bytes); + ASSERT_TRUE(response.ok()); + OfflineFrame message = FromBytes(bytes).result(); + EXPECT_THAT(message, EqualsProto(kExpected)); +} + +TEST(OfflineFramesTest, CanGenerateBwuWifiLanPathAvailable) { + constexpr char kExpected[] = + R"pb( + version: V1 + v1: < + type: BANDWIDTH_UPGRADE_NEGOTIATION + bandwidth_upgrade_negotiation: < + event_type: UPGRADE_PATH_AVAILABLE + upgrade_path_info: < + medium: WIFI_LAN + wifi_lan_socket: < ip_address: "\x01\x02\x03\x04" wifi_port: 1234 > + > + > + >)pb"; + ByteArray bytes = ForBwuWifiLanPathAvailable("\x01\x02\x03\x04", 1234); + auto response = FromBytes(bytes); + ASSERT_TRUE(response.ok()); + OfflineFrame message = FromBytes(bytes).result(); + EXPECT_THAT(message, EqualsProto(kExpected)); +} + +TEST(OfflineFramesTest, CanGenerateBwuBluetoothPathAvailable) { + constexpr char kExpected[] = + R"pb( + version: V1 + v1: < + type: BANDWIDTH_UPGRADE_NEGOTIATION + bandwidth_upgrade_negotiation: < + event_type: UPGRADE_PATH_AVAILABLE + upgrade_path_info: < + medium: BLUETOOTH + bluetooth_credentials: < + service_name: "service" + mac_address: "\x11\x22\x33\x44\x55\x66" + > + > + > + >)pb"; + ByteArray bytes = + ForBwuBluetoothPathAvailable("service", "\x11\x22\x33\x44\x55\x66"); + auto response = FromBytes(bytes); + ASSERT_TRUE(response.ok()); + OfflineFrame message = FromBytes(bytes).result(); + EXPECT_THAT(message, EqualsProto(kExpected)); +} + +TEST(OfflineFramesTest, CanGenerateBwuLastWrite) { + constexpr char kExpected[] = + R"pb( + version: V1 + v1: < + type: BANDWIDTH_UPGRADE_NEGOTIATION + bandwidth_upgrade_negotiation: < event_type: LAST_WRITE_TO_PRIOR_CHANNEL > + >)pb"; + ByteArray bytes = ForBwuLastWrite(); + auto response = FromBytes(bytes); + ASSERT_TRUE(response.ok()); + OfflineFrame message = FromBytes(bytes).result(); + EXPECT_THAT(message, EqualsProto(kExpected)); +} + +TEST(OfflineFramesTest, CanGenerateBwuSafeToClose) { + constexpr char kExpected[] = + R"pb( + version: V1 + v1: < + type: BANDWIDTH_UPGRADE_NEGOTIATION + bandwidth_upgrade_negotiation: < event_type: SAFE_TO_CLOSE_PRIOR_CHANNEL > + >)pb"; + ByteArray bytes = ForBwuSafeToClose(); + auto response = FromBytes(bytes); + ASSERT_TRUE(response.ok()); + OfflineFrame message = FromBytes(bytes).result(); + EXPECT_THAT(message, EqualsProto(kExpected)); +} + +TEST(OfflineFramesTest, CanGenerateBwuIntroduction) { + constexpr char kExpected[] = + R"pb( + version: V1 + v1: < + type: BANDWIDTH_UPGRADE_NEGOTIATION + bandwidth_upgrade_negotiation: < + event_type: CLIENT_INTRODUCTION + client_introduction: < endpoint_id: "ABC" > + > + >)pb"; + ByteArray bytes = ForBwuIntroduction(std::string(kEndpointId)); + auto response = FromBytes(bytes); + ASSERT_TRUE(response.ok()); + OfflineFrame message = FromBytes(bytes).result(); + EXPECT_THAT(message, EqualsProto(kExpected)); +} + +TEST(OfflineFramesTest, CanGenerateKeepAlive) { + constexpr char kExpected[] = + R"pb( + version: V1 + v1: < + type: KEEP_ALIVE + keep_alive: <> + >)pb"; + ByteArray bytes = ForKeepAlive(); + auto response = FromBytes(bytes); + ASSERT_TRUE(response.ok()); + OfflineFrame message = FromBytes(bytes).result(); + EXPECT_THAT(message, EqualsProto(kExpected)); } } // namespace - -TEST(OfflineFramesTest, CanParseMessageFromBytes) { - const std::string endpoint_id{"ABC"}; - const std::string endpoint_name{"XYZ"}; - const int32 nonce{1234}; - const std::vector mediums{Medium::BLE, - Medium::BLUETOOTH}; - - auto* v1_frame = new V1Frame{}; - auto* sub_frame = new ConnectionRequestFrame{}; - sub_frame->set_endpoint_id(endpoint_id); - sub_frame->set_endpoint_name(endpoint_name); - sub_frame->set_nonce(nonce); - - for (auto& medium : mediums) { - sub_frame->add_mediums(ToConnectionRequestMedium(medium)); - } - - SetSubframe(v1_frame, sub_frame); - auto frame = MakeFrame(v1_frame); - - auto bytes = MakeConstPtr(new ByteArray(frame->SerializeAsString())); - - auto ret_value = OfflineFrames::fromBytes(bytes); - ASSERT_TRUE(ret_value.ok()); - const auto& rx_message = ret_value.result(); - ASSERT_TRUE(rx_message->has_version()); - ASSERT_EQ(rx_message->version(), OfflineFrame::V1); - ASSERT_TRUE(rx_message->has_v1()); - const auto& rx_frame = rx_message->v1(); - ASSERT_EQ(rx_frame.type(), V1Frame::CONNECTION_REQUEST); - ASSERT_TRUE(rx_frame.has_connection_request()); - const auto& req = rx_frame.connection_request(); - ASSERT_TRUE(req.has_endpoint_id()); - ASSERT_TRUE(req.has_endpoint_name()); - ASSERT_TRUE(req.has_nonce()); - ASSERT_EQ(req.endpoint_id(), endpoint_id); - ASSERT_EQ(req.endpoint_name(), endpoint_name); - ASSERT_EQ(req.nonce(), nonce); - ASSERT_EQ(req.mediums_size(), mediums.size()); -} - -} // namespace location::nearby::connections +} // namespace parser +} // namespace connections +} // namespace nearby +} // namespace location diff --git a/cpp/core/internal/offline_service_controller.cc b/cpp/core/internal/offline_service_controller.cc index 386eb171..c1008a4f 100644 --- a/cpp/core/internal/offline_service_controller.cc +++ b/cpp/core/internal/offline_service_controller.cc @@ -6,103 +6,79 @@ namespace location { namespace nearby { namespace connections { -template -OfflineServiceController::OfflineServiceController() - : ServiceController(), - medium_manager_(new MediumManager()), - endpoint_channel_manager_( - new EndpointChannelManager(medium_manager_.get())), - endpoint_manager_( - new EndpointManager(endpoint_channel_manager_.get())), - payload_manager_(new PayloadManager(endpoint_manager_.get())), - bandwidth_upgrade_manager_(new BandwidthUpgradeManager( - medium_manager_.get(), endpoint_channel_manager_.get(), - endpoint_manager_.get())), - pcp_manager_(new PCPManager( - medium_manager_.get(), endpoint_channel_manager_.get(), - endpoint_manager_.get(), bandwidth_upgrade_manager_.get())) {} +OfflineServiceController::~OfflineServiceController() { Stop(); } -template -OfflineServiceController::~OfflineServiceController() {} - -template -Status::Value OfflineServiceController::startAdvertising( - Ptr > client_proxy, const string& endpoint_name, - const string& service_id, const AdvertisingOptions& advertising_options, - Ptr connection_lifecycle_listener) { - return pcp_manager_->startAdvertising(client_proxy, endpoint_name, service_id, - advertising_options, - connection_lifecycle_listener); +void OfflineServiceController::Stop() { + if (stop_.Set(true)) return; + payload_manager_.DisconnectFromEndpointManager(); + pcp_manager_.DisconnectFromEndpointManager(); } -template -void OfflineServiceController::stopAdvertising( - Ptr > client_proxy) { - pcp_manager_->stopAdvertising(client_proxy); +Status OfflineServiceController::StartAdvertising( + ClientProxy* client, const std::string& service_id, + const ConnectionOptions& options, const ConnectionRequestInfo& info) { + return pcp_manager_.StartAdvertising(client, service_id, options, info); } -template -Status::Value OfflineServiceController::startDiscovery( - Ptr > client_proxy, const string& service_id, - const DiscoveryOptions& discovery_options, - Ptr discovery_listener) { - return pcp_manager_->startDiscovery(client_proxy, service_id, - discovery_options, discovery_listener); +void OfflineServiceController::StopAdvertising(ClientProxy* client) { + pcp_manager_.StopAdvertising(client); } -template -void OfflineServiceController::stopDiscovery( - Ptr > client_proxy) { - pcp_manager_->stopDiscovery(client_proxy); +Status OfflineServiceController::StartDiscovery( + ClientProxy* client, const std::string& service_id, + const ConnectionOptions& options, const DiscoveryListener& listener) { + return pcp_manager_.StartDiscovery(client, service_id, options, listener); } -template -Status::Value OfflineServiceController::requestConnection( - Ptr > client_proxy, const string& endpoint_name, - const string& endpoint_id, - Ptr connection_lifecycle_listener) { - return pcp_manager_->requestConnection( - client_proxy, endpoint_name, endpoint_id, connection_lifecycle_listener); +void OfflineServiceController::StopDiscovery(ClientProxy* client) { + pcp_manager_.StopDiscovery(client); } -template -Status::Value OfflineServiceController::acceptConnection( - Ptr > client_proxy, const string& endpoint_id, - Ptr payload_listener) { - return pcp_manager_->acceptConnection(client_proxy, endpoint_id, - payload_listener); +void OfflineServiceController::InjectEndpoint( + ClientProxy* client, const std::string& service_id, + const OutOfBandConnectionMetadata& metadata) { + pcp_manager_.InjectEndpoint(client, service_id, metadata); } -template -Status::Value OfflineServiceController::rejectConnection( - Ptr > client_proxy, const string& endpoint_id) { - return pcp_manager_->rejectConnection(client_proxy, endpoint_id); +Status OfflineServiceController::RequestConnection( + ClientProxy* client, const std::string& endpoint_id, + const ConnectionRequestInfo& info, const ConnectionOptions& options) { + return pcp_manager_.RequestConnection(client, endpoint_id, info, options); } -template -void OfflineServiceController::initiateBandwidthUpgrade( - Ptr > client_proxy, const string& endpoint_id) { - bandwidth_upgrade_manager_->initiateBandwidthUpgradeForEndpoint( - client_proxy, endpoint_id, pcp_manager_->getBandwidthUpgradeMedium()); +Status OfflineServiceController::AcceptConnection( + ClientProxy* client, const std::string& endpoint_id, + const PayloadListener& listener) { + return pcp_manager_.AcceptConnection(client, endpoint_id, listener); } -template -void OfflineServiceController::sendPayload( - Ptr > client_proxy, - const std::vector& endpoint_ids, ConstPtr payload) { - payload_manager_->sendPayload(client_proxy, endpoint_ids, payload); +Status OfflineServiceController::RejectConnection( + ClientProxy* client, const std::string& endpoint_id) { + return pcp_manager_.RejectConnection(client, endpoint_id); } -template -Status::Value OfflineServiceController::cancelPayload( - Ptr > client_proxy, std::int64_t payload_id) { - return payload_manager_->cancelPayload(client_proxy, payload_id); +void OfflineServiceController::InitiateBandwidthUpgrade( + ClientProxy* client, const std::string& endpoint_id) { + NEARBY_LOGS(INFO) << "Client " << client->GetClientId() + << " initiated a manual bandwidth upgrade with endpoint id=" + << endpoint_id; + bwu_manager_.InitiateBwuForEndpoint(client, endpoint_id); } -template -void OfflineServiceController::disconnectFromEndpoint( - Ptr > client_proxy, const string& endpoint_id) { - endpoint_manager_->unregisterEndpoint(client_proxy, endpoint_id); +void OfflineServiceController::SendPayload( + ClientProxy* client, const std::vector& endpoint_ids, + Payload payload) { + payload_manager_.SendPayload(client, endpoint_ids, std::move(payload)); +} + +Status OfflineServiceController::CancelPayload(ClientProxy* client, + std::int64_t payload_id) { + return payload_manager_.CancelPayload(client, payload_id); +} + +void OfflineServiceController::DisconnectFromEndpoint( + ClientProxy* client, const std::string& endpoint_id) { + endpoint_manager_.UnregisterEndpoint(client, endpoint_id); } } // namespace connections diff --git a/cpp/core/internal/offline_service_controller.h b/cpp/core/internal/offline_service_controller.h index cbf1b13b..2a70eef4 100644 --- a/cpp/core/internal/offline_service_controller.h +++ b/cpp/core/internal/offline_service_controller.h @@ -2,13 +2,14 @@ #define CORE_INTERNAL_OFFLINE_SERVICE_CONTROLLER_H_ #include +#include #include -#include "core/internal/bandwidth_upgrade_manager.h" +#include "core/internal/bwu_manager.h" #include "core/internal/client_proxy.h" #include "core/internal/endpoint_channel_manager.h" #include "core/internal/endpoint_manager.h" -#include "core/internal/medium_manager.h" +#include "core/internal/mediums/mediums.h" #include "core/internal/payload_manager.h" #include "core/internal/pcp_manager.h" #include "core/internal/service_controller.h" @@ -16,69 +17,68 @@ #include "core/options.h" #include "core/payload.h" #include "core/status.h" -#include "platform/port/string.h" -#include "platform/ptr.h" namespace location { namespace nearby { namespace connections { -template -class OfflineServiceController : public ServiceController { +class OfflineServiceController : public ServiceController { public: - OfflineServiceController(); + OfflineServiceController() = default; ~OfflineServiceController() override; - Status::Value startAdvertising( - Ptr > client_proxy, const string& endpoint_name, - const string& service_id, const AdvertisingOptions& advertising_options, - Ptr connection_lifecycle_listener) override; - void stopAdvertising(Ptr > client_proxy) override; + Status StartAdvertising(ClientProxy* client, const std::string& service_id, + const ConnectionOptions& options, + const ConnectionRequestInfo& info) override; + void StopAdvertising(ClientProxy* client) override; - Status::Value startDiscovery( - Ptr > client_proxy, const string& service_id, - const DiscoveryOptions& discovery_options, - Ptr discovery_listener) override; - void stopDiscovery(Ptr > client_proxy) override; + Status StartDiscovery(ClientProxy* client, const std::string& service_id, + const ConnectionOptions& options, + const DiscoveryListener& listener) override; + void StopDiscovery(ClientProxy* client) override; - Status::Value requestConnection( - Ptr > client_proxy, const string& endpoint_name, - const string& endpoint_id, - Ptr connection_lifecycle_listener) override; - Status::Value acceptConnection( - Ptr > client_proxy, const string& endpoint_id, - Ptr payload_listener) override; - Status::Value rejectConnection(Ptr > client_proxy, - const string& endpoint_id) override; + void InjectEndpoint(ClientProxy* client, + const std::string& service_id, + const OutOfBandConnectionMetadata& metadata) override; - void initiateBandwidthUpgrade(Ptr > client_proxy, - const string& endpoint_id) override; + Status RequestConnection(ClientProxy* client, const std::string& endpoint_id, + const ConnectionRequestInfo& info, + const ConnectionOptions& options) override; + Status AcceptConnection(ClientProxy* client, const std::string& endpoint_id, + const PayloadListener& listener) override; + Status RejectConnection(ClientProxy* client, + const std::string& endpoint_id) override; - void sendPayload(Ptr > client_proxy, - const std::vector& endpoint_ids, - ConstPtr payload) override; - Status::Value cancelPayload(Ptr > client_proxy, - std::int64_t payload_id) override; + void InitiateBandwidthUpgrade(ClientProxy* client, + const std::string& endpoint_id) override; - void disconnectFromEndpoint(Ptr > client_proxy, - const string& endpoint_id) override; + void SendPayload(ClientProxy* client, + const std::vector& endpoint_ids, + Payload payload) override; + Status CancelPayload(ClientProxy* client, Payload::Id payload_id) override; + + void DisconnectFromEndpoint(ClientProxy* client, + const std::string& endpoint_id) override; + + void Stop(); private: // Note that the order of declaration of these is crucial, because we depend // on the destructors running (strictly) in the reverse order; a deviation // from that will lead to crashes at runtime. - ScopedPtr > > medium_manager_; - ScopedPtr> endpoint_channel_manager_; - ScopedPtr > > endpoint_manager_; - ScopedPtr > > payload_manager_; - ScopedPtr> bandwidth_upgrade_manager_; - ScopedPtr > > pcp_manager_; + AtomicBoolean stop_{false}; + Mediums mediums_; + EndpointChannelManager channel_manager_; + EndpointManager endpoint_manager_{&channel_manager_}; + PayloadManager payload_manager_{endpoint_manager_}; + BwuManager bwu_manager_{ + mediums_, endpoint_manager_, channel_manager_, {}, {}}; + PcpManager pcp_manager_{mediums_, channel_manager_, endpoint_manager_, + bwu_manager_}; }; } // namespace connections } // namespace nearby } // namespace location -#include "core/internal/offline_service_controller.cc" - #endif // CORE_INTERNAL_OFFLINE_SERVICE_CONTROLLER_H_ diff --git a/cpp/core_v2/internal/offline_service_controller_test.cc b/cpp/core/internal/offline_service_controller_test.cc similarity index 90% rename from cpp/core_v2/internal/offline_service_controller_test.cc rename to cpp/core/internal/offline_service_controller_test.cc index b7286cdf..e88859cd 100644 --- a/cpp/core_v2/internal/offline_service_controller_test.cc +++ b/cpp/core/internal/offline_service_controller_test.cc @@ -1,12 +1,14 @@ -#include "core_v2/internal/offline_service_controller.h" +#include "core/internal/offline_service_controller.h" -#include "core_v2/internal/offline_simulation_user.h" -#include "platform_v2/base/medium_environment.h" -#include "platform_v2/base/output_stream.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/logging.h" -#include "platform_v2/public/pipe.h" -#include "platform_v2/public/system_clock.h" +#include + +#include "core/internal/offline_simulation_user.h" +#include "platform/base/medium_environment.h" +#include "platform/base/output_stream.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/logging.h" +#include "platform/public/pipe.h" +#include "platform/public/system_clock.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -17,6 +19,7 @@ namespace { using ::testing::Eq; +constexpr std::array kFakeMacAddress = {'a', 'b', 'c', 'd', 'e', 'f'}; constexpr absl::string_view kServiceId = "service-id"; constexpr absl::string_view kDeviceA = "device-a"; constexpr absl::string_view kDeviceB = "device-b"; @@ -344,6 +347,27 @@ INSTANTIATE_TEST_SUITE_P(ParametrisedOfflineServiceControllerTest, OfflineServiceControllerTest, ::testing::ValuesIn(kTestCases)); +// Verifies that InjectEndpoint() can be run successfully; does not test the +// full connection flow given that normal discovery/advertisement is skipped. +// Note: Not parameterized because InjectEndpoint only works over Bluetooth. +TEST_F(OfflineServiceControllerTest, InjectEndpoint) { + env_.Start(); + OfflineSimulationUser user_a(kDeviceA, + BooleanMediumSelector{.bluetooth = true}); + EXPECT_THAT(user_a.StartDiscovery(std::string(kServiceId), + /*found_latch=*/nullptr), + Eq(Status{Status::kSuccess})); + EXPECT_TRUE(user_a.IsDiscovering()); + user_a.InjectEndpoint( + std::string(kServiceId), + OutOfBandConnectionMetadata{ + .medium = Medium::BLUETOOTH, + .remote_bluetooth_mac_address = ByteArray(kFakeMacAddress), + }); + user_a.Stop(); + env_.Stop(); +} + } // namespace } // namespace connections } // namespace nearby diff --git a/cpp/core/internal/offline_service_controller_test.cc.orig b/cpp/core/internal/offline_service_controller_test.cc.orig new file mode 100644 index 00000000..da1d51bd --- /dev/null +++ b/cpp/core/internal/offline_service_controller_test.cc.orig @@ -0,0 +1,374 @@ +#include "core_v2/internal/offline_service_controller.h" + +#include + +#include "core_v2/internal/offline_simulation_user.h" +#include "platform_v2/base/medium_environment.h" +#include "platform_v2/base/output_stream.h" +#include "platform_v2/public/count_down_latch.h" +#include "platform_v2/public/logging.h" +#include "platform_v2/public/pipe.h" +#include "platform_v2/public/system_clock.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace location { +namespace nearby { +namespace connections { +namespace { + +using ::testing::Eq; + +constexpr std::array kFakeMacAddress = {'a', 'b', 'c', 'd', 'e', 'f'}; +constexpr absl::string_view kServiceId = "service-id"; +constexpr absl::string_view kDeviceA = "device-a"; +constexpr absl::string_view kDeviceB = "device-b"; +constexpr absl::string_view kMessage = "message"; +constexpr absl::Duration kProgressTimeout = absl::Milliseconds(1000); +constexpr absl::Duration kDefaultTimeout = absl::Milliseconds(1000); +constexpr absl::Duration kDisconnectTimeout = absl::Milliseconds(15000); + +constexpr BooleanMediumSelector kTestCases[] = { + BooleanMediumSelector{ + .bluetooth = true, + }, + BooleanMediumSelector{ + .wifi_lan = true, + }, + BooleanMediumSelector{ + .bluetooth = true, + .wifi_lan = true, + }, +}; + +class OfflineServiceControllerTest + : public ::testing::TestWithParam { + protected: + OfflineServiceControllerTest() { env_.Stop(); } + + bool SetupConnection(OfflineSimulationUser& user_a, + OfflineSimulationUser& user_b) { + user_a.StartAdvertising(std::string(kServiceId), &connect_latch_); + user_b.StartDiscovery(std::string(kServiceId), &discover_latch_); + EXPECT_TRUE(discover_latch_.Await(kDefaultTimeout).result()); + EXPECT_EQ(user_b.GetDiscovered().service_id, kServiceId); + EXPECT_EQ(user_b.GetDiscovered().endpoint_info, user_a.GetInfo()); + EXPECT_FALSE(user_b.GetDiscovered().endpoint_id.empty()); + NEARBY_LOG(INFO, "EP-B: [discovered] %s", + user_b.GetDiscovered().endpoint_id.c_str()); + user_b.RequestConnection(&connect_latch_); + EXPECT_TRUE(connect_latch_.Await(kDefaultTimeout).result()); + EXPECT_FALSE(user_a.GetDiscovered().endpoint_id.empty()); + NEARBY_LOG(INFO, "EP-A: [discovered] %s", + user_a.GetDiscovered().endpoint_id.c_str()); + NEARBY_LOG(INFO, "Both users discovered their peers."); + user_a.AcceptConnection(&accept_latch_); + user_b.AcceptConnection(&accept_latch_); + EXPECT_TRUE(accept_latch_.Await(kDefaultTimeout).result()); + NEARBY_LOG(INFO, "Both users reached connected state."); + return user_a.IsConnected() && user_b.IsConnected(); + } + + CountDownLatch discover_latch_{1}; + CountDownLatch lost_latch_{1}; + CountDownLatch connect_latch_{2}; + CountDownLatch accept_latch_{2}; + CountDownLatch payload_latch_{1}; + MediumEnvironment& env_ = MediumEnvironment::Instance(); +}; + +TEST_P(OfflineServiceControllerTest, CanCreateOne) { + env_.Start(); + OfflineSimulationUser user_a(kDeviceA, GetParam()); + env_.Stop(); +} + +TEST_P(OfflineServiceControllerTest, CanCreateMany) { + env_.Start(); + OfflineSimulationUser user_a(kDeviceA, GetParam()); + OfflineSimulationUser user_b(kDeviceB, GetParam()); + env_.Stop(); +} + +TEST_P(OfflineServiceControllerTest, CanStartAdvertising) { + env_.Start(); + OfflineSimulationUser user_a(kDeviceA, GetParam()); + OfflineSimulationUser user_b(kDeviceB, GetParam()); + EXPECT_FALSE(user_a.IsAdvertising()); + EXPECT_THAT(user_a.StartAdvertising(std::string(kServiceId), nullptr), + Eq(Status{Status::kSuccess})); + EXPECT_TRUE(user_a.IsAdvertising()); + env_.Stop(); +} + +TEST_P(OfflineServiceControllerTest, CanStartDiscoveryBeforeAdvertising) { + env_.Start(); + OfflineSimulationUser user_a(kDeviceA, GetParam()); + OfflineSimulationUser user_b(kDeviceB, GetParam()); + EXPECT_FALSE(user_b.IsDiscovering()); + EXPECT_THAT(user_b.StartDiscovery(std::string(kServiceId), &discover_latch_), + Eq(Status{Status::kSuccess})); + EXPECT_TRUE(user_b.IsDiscovering()); + EXPECT_THAT(user_a.StartAdvertising(std::string(kServiceId), nullptr), + Eq(Status{Status::kSuccess})); + EXPECT_TRUE(discover_latch_.Await(kDefaultTimeout).result()); + user_a.Stop(); + user_b.Stop(); + env_.Stop(); +} + +TEST_P(OfflineServiceControllerTest, CanStartDiscoveryAfterAdvertising) { + env_.Start(); + OfflineSimulationUser user_a(kDeviceA, GetParam()); + OfflineSimulationUser user_b(kDeviceB, GetParam()); + EXPECT_FALSE(user_b.IsDiscovering()); + EXPECT_FALSE(user_b.IsAdvertising()); + EXPECT_THAT(user_a.StartAdvertising(std::string(kServiceId), nullptr), + Eq(Status{Status::kSuccess})); + EXPECT_THAT(user_b.StartDiscovery(std::string(kServiceId), &discover_latch_), + Eq(Status{Status::kSuccess})); + EXPECT_TRUE(user_a.IsAdvertising()); + EXPECT_TRUE(user_b.IsDiscovering()); + EXPECT_TRUE(discover_latch_.Await(kDefaultTimeout).result()); + user_a.Stop(); + user_b.Stop(); + env_.Stop(); +} + +TEST_P(OfflineServiceControllerTest, CanStopAdvertising) { + env_.Start(); + OfflineSimulationUser user_a(kDeviceA, GetParam()); + OfflineSimulationUser user_b(kDeviceB, GetParam()); + EXPECT_FALSE(user_a.IsAdvertising()); + EXPECT_THAT(user_a.StartAdvertising(std::string(kServiceId), nullptr), + Eq(Status{Status::kSuccess})); + EXPECT_TRUE(user_a.IsAdvertising()); + user_a.StopAdvertising(); + EXPECT_FALSE(user_a.IsAdvertising()); + EXPECT_THAT(user_b.StartDiscovery(std::string(kServiceId), &discover_latch_, + &lost_latch_), + Eq(Status{Status::kSuccess})); + EXPECT_TRUE(user_b.IsDiscovering()); + auto discover_none = discover_latch_.Await(kDefaultTimeout).GetResult(); + if (!discover_none) { + EXPECT_TRUE(true); + } else { + // There are rare cases (1/1000) that advertisment data has been captured by + // discovery device before advertising is stopped. So we need to check if + // lost_cb has grabbed the event in the end to prove the advertising service + // is stopped. + EXPECT_TRUE(lost_latch_.Await(kDefaultTimeout).result()); + } + user_a.Stop(); + user_b.Stop(); + env_.Stop(); +} + +TEST_P(OfflineServiceControllerTest, CanStopDiscovery) { + env_.Start(); + OfflineSimulationUser user_a(kDeviceA, GetParam()); + OfflineSimulationUser user_b(kDeviceB, GetParam()); + EXPECT_FALSE(user_b.IsDiscovering()); + EXPECT_THAT(user_b.StartDiscovery(std::string(kServiceId), &discover_latch_), + Eq(Status{Status::kSuccess})); + EXPECT_TRUE(user_b.IsDiscovering()); + user_b.StopDiscovery(); + EXPECT_FALSE(user_b.IsDiscovering()); + EXPECT_THAT(user_a.StartAdvertising(std::string(kServiceId), nullptr), + Eq(Status{Status::kSuccess})); + EXPECT_FALSE(discover_latch_.Await(kDefaultTimeout).result()); + user_a.Stop(); + user_b.Stop(); + env_.Stop(); +} + +TEST_P(OfflineServiceControllerTest, CanConnect) { + env_.Start(); + OfflineSimulationUser user_a(kDeviceA, GetParam()); + OfflineSimulationUser user_b(kDeviceB, GetParam()); + EXPECT_THAT(user_a.StartAdvertising(std::string(kServiceId), &connect_latch_), + Eq(Status{Status::kSuccess})); + EXPECT_THAT(user_b.StartDiscovery(std::string(kServiceId), &discover_latch_), + Eq(Status{Status::kSuccess})); + EXPECT_TRUE(discover_latch_.Await(kDefaultTimeout).result()); + EXPECT_THAT(user_b.RequestConnection(&connect_latch_), + Eq(Status{Status::kSuccess})); + EXPECT_TRUE(connect_latch_.Await(kDefaultTimeout).result()); + user_a.Stop(); + user_b.Stop(); + env_.Stop(); +} + +TEST_P(OfflineServiceControllerTest, CanAcceptConnection) { + env_.Start(); + OfflineSimulationUser user_a(kDeviceA, GetParam()); + OfflineSimulationUser user_b(kDeviceB, GetParam()); + EXPECT_THAT(user_a.StartAdvertising(std::string(kServiceId), &connect_latch_), + Eq(Status{Status::kSuccess})); + EXPECT_THAT(user_b.StartDiscovery(std::string(kServiceId), &discover_latch_), + Eq(Status{Status::kSuccess})); + EXPECT_TRUE(discover_latch_.Await(kDefaultTimeout).result()); + EXPECT_THAT(user_b.RequestConnection(&connect_latch_), + Eq(Status{Status::kSuccess})); + EXPECT_TRUE(connect_latch_.Await(kDefaultTimeout).result()); + EXPECT_THAT(user_a.AcceptConnection(&accept_latch_), + Eq(Status{Status::kSuccess})); + EXPECT_THAT(user_b.AcceptConnection(&accept_latch_), + Eq(Status{Status::kSuccess})); + EXPECT_TRUE(accept_latch_.Await(kDefaultTimeout).result()); + EXPECT_TRUE(user_a.IsConnected()); + EXPECT_TRUE(user_b.IsConnected()); + user_a.Stop(); + user_b.Stop(); + env_.Stop(); +} + +TEST_P(OfflineServiceControllerTest, CanRejectConnection) { + env_.Start(); + OfflineSimulationUser user_a(kDeviceA, GetParam()); + OfflineSimulationUser user_b(kDeviceB, GetParam()); + CountDownLatch reject_latch(1); + EXPECT_THAT(user_a.StartAdvertising(std::string(kServiceId), &connect_latch_), + Eq(Status{Status::kSuccess})); + EXPECT_THAT(user_b.StartDiscovery(std::string(kServiceId), &discover_latch_), + Eq(Status{Status::kSuccess})); + EXPECT_TRUE(discover_latch_.Await(kDefaultTimeout).result()); + EXPECT_THAT(user_b.RequestConnection(&connect_latch_), + Eq(Status{Status::kSuccess})); + EXPECT_TRUE(connect_latch_.Await(kDefaultTimeout).result()); + user_a.ExpectRejectedConnection(reject_latch); + EXPECT_THAT(user_b.RejectConnection(nullptr), Eq(Status{Status::kSuccess})); + EXPECT_TRUE(reject_latch.Await(kDefaultTimeout).result()); + user_a.Stop(); + user_b.Stop(); + env_.Stop(); +} + +TEST_P(OfflineServiceControllerTest, CanSendBytePayload) { + env_.Start(); + OfflineSimulationUser user_a(kDeviceA, GetParam()); + OfflineSimulationUser user_b(kDeviceB, GetParam()); + ASSERT_TRUE(SetupConnection(user_a, user_b)); + ByteArray message(std::string{kMessage}); + user_a.SendPayload(Payload(message)); + user_b.ExpectPayload(payload_latch_); + EXPECT_TRUE(payload_latch_.Await(kDefaultTimeout).result()); + EXPECT_EQ(user_b.GetPayload().AsBytes(), message); + user_a.Stop(); + user_b.Stop(); + env_.Stop(); +} + +TEST_P(OfflineServiceControllerTest, CanSendStreamPayload) { + env_.Start(); + OfflineSimulationUser user_a(kDeviceA, GetParam()); + OfflineSimulationUser user_b(kDeviceB, GetParam()); + ASSERT_TRUE(SetupConnection(user_a, user_b)); + ByteArray message(std::string{kMessage}); + auto pipe = std::make_shared(); + OutputStream& tx = pipe->GetOutputStream(); + user_a.SendPayload(Payload([pipe]() -> InputStream& { + return pipe->GetInputStream(); // NOLINT + })); + user_b.ExpectPayload(payload_latch_); + tx.Write(message); + EXPECT_TRUE(payload_latch_.Await(kDefaultTimeout).result()); + EXPECT_NE(user_b.GetPayload().AsStream(), nullptr); + InputStream& rx = *user_b.GetPayload().AsStream(); + ASSERT_TRUE(user_b.WaitForProgress( + [size = message.size()](const PayloadProgressInfo& info) -> bool { + return info.bytes_transferred >= size; + }, + kProgressTimeout)); + EXPECT_EQ(rx.Read(Pipe::kChunkSize).result(), message); + user_a.Stop(); + user_b.Stop(); + env_.Stop(); +} + +TEST_P(OfflineServiceControllerTest, CanCancelStreamPayload) { + env_.Start(); + OfflineSimulationUser user_a(kDeviceA, GetParam()); + OfflineSimulationUser user_b(kDeviceB, GetParam()); + ASSERT_TRUE(SetupConnection(user_a, user_b)); + ByteArray message(std::string{kMessage}); + auto pipe = std::make_shared(); + OutputStream& tx = pipe->GetOutputStream(); + user_a.SendPayload(Payload([pipe]() -> InputStream& { + return pipe->GetInputStream(); // NOLINT + })); + user_b.ExpectPayload(payload_latch_); + tx.Write(message); + EXPECT_TRUE(payload_latch_.Await(kDefaultTimeout).result()); + EXPECT_NE(user_b.GetPayload().AsStream(), nullptr); + InputStream& rx = *user_b.GetPayload().AsStream(); + ASSERT_TRUE(user_b.WaitForProgress( + [size = message.size()](const PayloadProgressInfo& info) -> bool { + return info.bytes_transferred >= size; + }, + kProgressTimeout)); + EXPECT_EQ(rx.Read(Pipe::kChunkSize).result(), message); + user_b.CancelPayload(); + int count = 0; + while (true) { + count++; + if (!tx.Write(message).Ok()) break; + SystemClock::Sleep(kDefaultTimeout); + } + EXPECT_TRUE(user_a.WaitForProgress( + [](const PayloadProgressInfo& info) -> bool { + return info.status == PayloadProgressInfo::Status::kCanceled; + }, + kProgressTimeout)); + EXPECT_LT(count, 10); + user_a.Stop(); + user_b.Stop(); + env_.Stop(); +} + +TEST_P(OfflineServiceControllerTest, CanDisconnect) { + env_.Start(); + CountDownLatch disconnect_latch(1); + OfflineSimulationUser user_a(kDeviceA, GetParam()); + OfflineSimulationUser user_b(kDeviceB, GetParam()); + ASSERT_TRUE(SetupConnection(user_a, user_b)); + NEARBY_LOGS(INFO) << "Disconnecting"; + user_b.ExpectDisconnect(disconnect_latch); + user_b.Disconnect(); + EXPECT_TRUE(disconnect_latch.Await(kDisconnectTimeout).result()); + NEARBY_LOGS(INFO) << "Disconnected"; + EXPECT_FALSE(user_b.IsConnected()); + user_a.Stop(); + user_b.Stop(); + env_.Stop(); +} + +INSTANTIATE_TEST_SUITE_P(ParametrisedOfflineServiceControllerTest, + OfflineServiceControllerTest, + ::testing::ValuesIn(kTestCases)); + +// Verifies that InjectEndpoint() can be run successfully; does not test the +// full connection flow given that normal discovery/advertisement is skipped. +// Note: Not parameterized because InjectEndpoint only works over Bluetooth. +TEST_F(OfflineServiceControllerTest, InjectEndpoint) { + env_.Start(); + OfflineSimulationUser user_a(kDeviceA, + BooleanMediumSelector{.bluetooth = true}); + EXPECT_THAT(user_a.StartDiscovery(std::string(kServiceId), + /*found_latch=*/nullptr), + Eq(Status{Status::kSuccess})); + EXPECT_TRUE(user_a.IsDiscovering()); + user_a.InjectEndpoint( + std::string(kServiceId), + OutOfBandConnectionMetadata{ + .medium = Medium::BLUETOOTH, + .remote_bluetooth_mac_address = ByteArray(kFakeMacAddress), + }); + user_a.Stop(); + env_.Stop(); +} + +} // namespace +} // namespace connections +} // namespace nearby +} // namespace location diff --git a/cpp/core_v2/internal/offline_simulation_user.cc b/cpp/core/internal/offline_simulation_user.cc similarity index 94% rename from cpp/core_v2/internal/offline_simulation_user.cc rename to cpp/core/internal/offline_simulation_user.cc index 4f79ac99..a7f712f2 100644 --- a/cpp/core_v2/internal/offline_simulation_user.cc +++ b/cpp/core/internal/offline_simulation_user.cc @@ -1,9 +1,9 @@ -#include "core_v2/internal/offline_simulation_user.h" +#include "core/internal/offline_simulation_user.h" -#include "core_v2/listeners.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/system_clock.h" +#include "core/listeners.h" +#include "platform/base/byte_array.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/system_clock.h" #include "absl/functional/bind_front.h" namespace location { @@ -134,6 +134,12 @@ Status OfflineSimulationUser::StartDiscovery(const std::string& service_id, void OfflineSimulationUser::StopDiscovery() { ctrl_.StopDiscovery(&client_); } +void OfflineSimulationUser::InjectEndpoint( + const std::string& service_id, + const OutOfBandConnectionMetadata& metadata) { + ctrl_.InjectEndpoint(&client_, service_id, metadata); +} + Status OfflineSimulationUser::RequestConnection(CountDownLatch* latch) { initiated_latch_ = latch; ConnectionListener listener = { diff --git a/cpp/core_v2/internal/offline_simulation_user.h b/cpp/core/internal/offline_simulation_user.h similarity index 90% rename from cpp/core_v2/internal/offline_simulation_user.h rename to cpp/core/internal/offline_simulation_user.h index 5b103b85..8e8b5b5e 100644 --- a/cpp/core_v2/internal/offline_simulation_user.h +++ b/cpp/core/internal/offline_simulation_user.h @@ -1,15 +1,15 @@ -#ifndef CORE_V2_INTERNAL_OFFLINE_SIMULATION_USER_H_ -#define CORE_V2_INTERNAL_OFFLINE_SIMULATION_USER_H_ +#ifndef CORE_INTERNAL_OFFLINE_SIMULATION_USER_H_ +#define CORE_INTERNAL_OFFLINE_SIMULATION_USER_H_ #include -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/offline_service_controller.h" -#include "core_v2/options.h" -#include "platform_v2/public/atomic_boolean.h" -#include "platform_v2/public/condition_variable.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/future.h" +#include "core/internal/client_proxy.h" +#include "core/internal/offline_service_controller.h" +#include "core/options.h" +#include "platform/public/atomic_boolean.h" +#include "platform/public/condition_variable.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/future.h" #include "gtest/gtest.h" #include "absl/strings/string_view.h" @@ -63,6 +63,10 @@ class OfflineSimulationUser { // Calls PcpManager::StopDiscovery(). void StopDiscovery(); + // 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. @@ -173,4 +177,4 @@ class OfflineSimulationUser { } // namespace nearby } // namespace location -#endif // CORE_V2_INTERNAL_OFFLINE_SIMULATION_USER_H_ +#endif // CORE_INTERNAL_OFFLINE_SIMULATION_USER_H_ diff --git a/cpp/core/internal/p2p_cluster_pcp_handler.cc b/cpp/core/internal/p2p_cluster_pcp_handler.cc index 3d73f236..864f290e 100644 --- a/cpp/core/internal/p2p_cluster_pcp_handler.cc +++ b/cpp/core/internal/p2p_cluster_pcp_handler.cc @@ -1,1097 +1,1228 @@ #include "core/internal/p2p_cluster_pcp_handler.h" -#include "platform/api/hash_utils.h" +#include "core/internal/base_pcp_handler.h" +#include "core/internal/ble_advertisement.h" +#include "core/internal/ble_endpoint_channel.h" +#include "core/internal/bluetooth_endpoint_channel.h" +#include "core/internal/bwu_manager.h" +#include "core/internal/mediums/utils.h" +#include "core/internal/mediums/webrtc/webrtc_socket_wrapper.h" +#include "core/internal/webrtc_endpoint_channel.h" +#include "core/internal/wifi_lan_endpoint_channel.h" +#include "platform/base/types.h" +#include "platform/public/crypto.h" +#include "proto/connections_enums.pb.h" +#include "absl/functional/bind_front.h" +#include "absl/strings/escaping.h" namespace location { namespace nearby { namespace connections { -template -const BluetoothDeviceName::Version::Value - P2PClusterPCPHandler::kBluetoothDeviceNameVersion = - BluetoothDeviceName::Version::V1; - -template -const BLEAdvertisement::Version::Value - P2PClusterPCPHandler::kBleAdvertisementVersion = - BLEAdvertisement::Version::V1; - -template -const WifiLanServiceInfo::Version - P2PClusterPCPHandler::kWifiLanServiceInfoVersion = - WifiLanServiceInfo::Version::kV1; - -template -ConstPtr P2PClusterPCPHandler::generateHash( - const string& source, size_t size) { - // Initiazing a new HashUtils each time instead of making it a class member - // because FoundBluetoothAdvertisementProcessor uses generateHash in its - // constructor so this method has to be static. We *could* make a static - // ScopedPtr for HashUtils, but that can get into dangerous territory in terms - // of time of destruction of that object, so we'll avoid it for now, and stick - // with this. - ScopedPtr> hash_utils(Platform::createHashUtils()); - - ScopedPtr> scoped_hash(hash_utils->sha256(source)); - return MakeConstPtr(new ByteArray(scoped_hash->getData(), size)); +ByteArray P2pClusterPcpHandler::GenerateHash(const std::string& source, + size_t size) { + return Utils::Sha256Hash(source, size); } -template -P2PClusterPCPHandler::P2PClusterPCPHandler( - Ptr> medium_manager, - Ptr> endpoint_manager, - Ptr endpoint_channel_manager, - Ptr bandwidth_upgrade_manager) - : BasePCPHandler(endpoint_manager, endpoint_channel_manager, - bandwidth_upgrade_manager), - medium_manager_(medium_manager) {} - -template -P2PClusterPCPHandler::~P2PClusterPCPHandler() {} - -template -Strategy P2PClusterPCPHandler::getStrategy() { - return Strategy::kP2PCluster; +bool P2pClusterPcpHandler::ShouldAdvertiseBluetoothMacOverBle( + PowerLevel power_level) { + return power_level == PowerLevel::kHighPower; } -template -PCP::Value P2PClusterPCPHandler::getPCP() { - return PCP::P2P_CLUSTER; +bool P2pClusterPcpHandler::ShouldAcceptBluetoothConnections( + const ConnectionOptions& options) { + return options.enable_bluetooth_listening; } -template +P2pClusterPcpHandler::P2pClusterPcpHandler( + Mediums* mediums, EndpointManager* endpoint_manager, + EndpointChannelManager* endpoint_channel_manager, BwuManager* bwu_manager, + Pcp pcp) + : BasePcpHandler(mediums, endpoint_manager, endpoint_channel_manager, + bwu_manager, pcp), + bluetooth_radio_(mediums->GetBluetoothRadio()), + bluetooth_medium_(mediums->GetBluetoothClassic()), + ble_medium_(mediums->GetBle()), + wifi_lan_medium_(mediums->GetWifiLan()), + webrtc_medium_(mediums->GetWebRtc()) {} + +// Returns a vector or mediums sorted in order or decreasing priority for +// all the supported mediums. +// Example: WiFi_LAN, WEB_RTC, BT, BLE std::vector -P2PClusterPCPHandler::getConnectionMediumsByPriority() { +P2pClusterPcpHandler::GetConnectionMediumsByPriority() { std::vector mediums; - if (medium_manager_->IsWifiLanAvailable()) { + if (wifi_lan_medium_.IsAvailable()) { mediums.push_back(proto::connections::WIFI_LAN); } - if (medium_manager_->isBluetoothAvailable()) { + if (webrtc_medium_.IsAvailable()) { + mediums.push_back(proto::connections::WEB_RTC); + } + if (bluetooth_medium_.IsAvailable()) { mediums.push_back(proto::connections::BLUETOOTH); } - if (medium_manager_->isBleAvailable()) { + if (ble_medium_.IsAvailable()) { mediums.push_back(proto::connections::BLE); } return mediums; } -template -proto::connections::Medium -P2PClusterPCPHandler::getDefaultUpgradeMedium() { +proto::connections::Medium P2pClusterPcpHandler::GetDefaultUpgradeMedium() { return proto::connections::WIFI_LAN; } -template -Ptr::StartOperationResult> -P2PClusterPCPHandler::startAdvertisingImpl( - Ptr> client_proxy, const string& service_id, - const string& local_endpoint_id, const string& local_endpoint_name, - const AdvertisingOptions& options) { +BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartAdvertisingImpl( + ClientProxy* client, const std::string& service_id, + const std::string& local_endpoint_id, const ByteArray& local_endpoint_info, + const ConnectionOptions& options) { std::vector mediums_started_successfully; - ScopedPtr> scoped_wifi_lan_service_id_hash( - generateHash(service_id, WifiLanServiceInfo::kServiceIdHashLength)); - proto::connections::Medium wifi_lan_medium = StartWifiLanAdvertising( - client_proxy, service_id, scoped_wifi_lan_service_id_hash.get(), - local_endpoint_id, local_endpoint_name); - if (proto::connections::UNKNOWN_MEDIUM != wifi_lan_medium) { - mediums_started_successfully.push_back(wifi_lan_medium); + WebRtcState web_rtc_state{WebRtcState::kUnconnectable}; + if (options.allowed.web_rtc) { + proto::connections::Medium webrtc_medium = + StartListeningForWebRtcConnections( + client, service_id, local_endpoint_id, local_endpoint_info); + if (webrtc_medium != proto::connections::UNKNOWN_MEDIUM) { + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::StartAdvertisingImpl: WebRtc added"); + mediums_started_successfully.push_back(webrtc_medium); + web_rtc_state = WebRtcState::kConnectable; + } } - ScopedPtr> scoped_bluetooth_service_id_hash( - generateHash(service_id, BluetoothDeviceName::kServiceIdHashLength)); - proto::connections::Medium bluetooth_medium = startBluetoothAdvertising( - client_proxy, service_id, scoped_bluetooth_service_id_hash.get(), - local_endpoint_id, local_endpoint_name); - if (proto::connections::UNKNOWN_MEDIUM != bluetooth_medium) { - mediums_started_successfully.push_back(bluetooth_medium); + if (options.allowed.wifi_lan) { + const ByteArray wifi_lan_hash = + GenerateHash(service_id, WifiLanServiceInfo::kServiceIdHashLength); + proto::connections::Medium wifi_lan_medium = StartWifiLanAdvertising( + client, service_id, wifi_lan_hash, local_endpoint_id, + local_endpoint_info, web_rtc_state); + if (wifi_lan_medium != proto::connections::UNKNOWN_MEDIUM) { + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::StartAdvertisingImpl: WifiLan added"); + mediums_started_successfully.push_back(wifi_lan_medium); + } } - ScopedPtr> scoped_ble_service_id_hash( - generateHash(service_id, BLEAdvertisement::kServiceIdHashLength)); - proto::connections::Medium ble_medium = startBleAdvertising( - client_proxy, service_id, scoped_ble_service_id_hash.get(), - local_endpoint_id, local_endpoint_name); - if (proto::connections::UNKNOWN_MEDIUM != ble_medium) { - mediums_started_successfully.push_back(ble_medium); + if (options.allowed.bluetooth) { + const ByteArray bluetooth_hash = + GenerateHash(service_id, BluetoothDeviceName::kServiceIdHashLength); + proto::connections::Medium bluetooth_medium = StartBluetoothAdvertising( + client, service_id, bluetooth_hash, local_endpoint_id, + local_endpoint_info, web_rtc_state); + if (bluetooth_medium != proto::connections::UNKNOWN_MEDIUM) { + NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartAdvertisingImpl: BT added"); + mediums_started_successfully.push_back(bluetooth_medium); + } + } + + if (options.allowed.ble) { + proto::connections::Medium ble_medium = + StartBleAdvertising(client, service_id, local_endpoint_id, + local_endpoint_info, options, web_rtc_state); + if (ble_medium != proto::connections::UNKNOWN_MEDIUM) { + NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartAdvertisingImpl: Ble added"); + mediums_started_successfully.push_back(ble_medium); + } } if (mediums_started_successfully.empty()) { - // TODO(tracyzhou): Add logging. - return BasePCPHandler::StartOperationResult::error( - Status::BLUETOOTH_ERROR); + NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartAdvertisingImpl: not started"); + return { + .status = {Status::kBluetoothError}, + }; } // The rest of the operations for startAdvertising() will continue // asynchronously via // IncomingBluetoothConnectionProcessor.onIncomingBluetoothConnection(), so // leave it to that to signal any errors that may occur. - return BasePCPHandler::StartOperationResult::success( - mediums_started_successfully); + return { + .status = {Status::kSuccess}, + .mediums = std::move(mediums_started_successfully), + }; } -template -Status::Value P2PClusterPCPHandler::stopAdvertisingImpl( - Ptr> client_proxy) { - medium_manager_->stopBleAdvertising(client_proxy->getAdvertisingServiceId()); - medium_manager_->turnOffBluetoothDiscoverability(); - medium_manager_->StopWifiLanAdvertising( - client_proxy->getAdvertisingServiceId()); - medium_manager_->stopListeningForIncomingBleConnections( - client_proxy->getAdvertisingServiceId()); - medium_manager_->stopListeningForIncomingBluetoothConnections( - client_proxy->getAdvertisingServiceId()); - medium_manager_->StopListeningForIncomingWifiLanConnections( - client_proxy->getAdvertisingServiceId()); - return Status::SUCCESS; +Status P2pClusterPcpHandler::StopAdvertisingImpl(ClientProxy* client) { + bluetooth_medium_.TurnOffDiscoverability(); + bluetooth_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId()); + + ble_medium_.StopAdvertising(client->GetAdvertisingServiceId()); + ble_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId()); + + webrtc_medium_.StopAcceptingConnections(); + + wifi_lan_medium_.StopAdvertising(client->GetAdvertisingServiceId()); + wifi_lan_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId()); + + return {Status::kSuccess}; } -template -Ptr::StartOperationResult> -P2PClusterPCPHandler::startDiscoveryImpl( - Ptr> client_proxy, const string& service_id, - const DiscoveryOptions& options) { +bool P2pClusterPcpHandler::IsRecognizedBluetoothEndpoint( + const std::string& name_string, const std::string& service_id, + const BluetoothDeviceName& name) const { + if (!name.IsValid()) { + NEARBY_LOG( + INFO, + "P2pClusterPcpHandler::IsRecognizedBluetoothEndpoint: name is invalid"); + return false; + } + + if (name.GetPcp() != GetPcp()) { + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::IsRecognizedBluetoothEndpoint: Pcp is " + "not matched; name.Pcp=%d, Pcp=%d", + name.GetPcp(), GetPcp()); + return false; + } + + ByteArray expected_service_id_hash = + GenerateHash(service_id, BluetoothDeviceName::kServiceIdHashLength); + + if (name.GetServiceIdHash() != expected_service_id_hash) { + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::IsRecognizedBluetoothEndpoint: service " + "id hash is " + "not matched; name.service_id_hash=%s, expected=%s", + name.GetServiceIdHash().data(), expected_service_id_hash.data()); + return false; + } + + return true; +} + +void P2pClusterPcpHandler::BluetoothDeviceDiscoveredHandler( + ClientProxy* client, const std::string& service_id, + BluetoothDevice& device) { + RunOnPcpHandlerThread([this, client, service_id, &device]() { + // Make sure we are still discovering before proceeding. + if (!client->IsDiscovering()) { + NEARBY_LOG(INFO, + "BT discovery handler (FOUND) [client=%p, service=%s]: not " + "in discovery mode", + client, service_id.c_str()); + return; + } + + // Parse the Bluetooth device name. + const std::string& device_name_string = device.GetName(); + BluetoothDeviceName device_name(device_name_string); + + // Make sure the Bluetooth device name points to a valid + // endpoint we're discovering. + if (!IsRecognizedBluetoothEndpoint(device_name_string, service_id, + device_name)) + return; + + // Report the discovered endpoint to the client. + NEARBY_LOGS(INFO) + << "Invoking BasePcpHandler::OnEndpointFound() for BT service=" + << service_id << "; id=" << device_name.GetEndpointId() << "; name=" + << absl::BytesToHexString(device_name.GetEndpointInfo().data()); + OnEndpointFound(client, + std::make_shared(BluetoothEndpoint{ + { + device_name.GetEndpointId(), + device_name.GetEndpointInfo(), + service_id, + proto::connections::Medium::BLUETOOTH, + device_name.GetWebRtcState() + }, + device, + })); + }); +} + +void P2pClusterPcpHandler::BluetoothDeviceLostHandler( + ClientProxy* client, const std::string& service_id, + BluetoothDevice& device) { + const std::string& device_name_string = device.GetName(); + RunOnPcpHandlerThread([this, client, service_id, device_name_string]() { + // Make sure we are still discovering before proceeding. + if (!client->IsDiscovering()) { + NEARBY_LOG(INFO, + "BT discovery handler (LOST) [client=%p, service=%s]: not " + "in discovery mode", + client, service_id.c_str()); + return; + } + + // Parse the Bluetooth device name. + BluetoothDeviceName device_name(device_name_string); + + // Make sure the Bluetooth device name points to a valid + // endpoint we're discovering. + if (!IsRecognizedBluetoothEndpoint(device_name_string, service_id, + device_name)) + return; + + // Report the discovered endpoint to the client. + NEARBY_LOG(INFO, + "BT discovery handler (LOST) [client=%p, service=%s]: report " + "to client", + client, service_id.c_str()); + OnEndpointLost(client, DiscoveredEndpoint{ + device_name.GetEndpointId(), + device_name.GetEndpointInfo(), + service_id, + proto::connections::Medium::BLUETOOTH, + WebRtcState::kUndefined + }); + }); +} + +bool P2pClusterPcpHandler::IsRecognizedBleEndpoint( + const std::string& service_id, + const BleAdvertisement& advertisement) const { + if (!advertisement.IsValid()) { + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::IsRecognizedBleEndpoint: advertisement " + "is invalid"); + return false; + } + + if (advertisement.GetVersion() != kBleAdvertisementVersion) { + NEARBY_LOG( + INFO, + "P2pClusterPcpHandler::IsRecognizedBluetoothEndpoint: Version is " + "not matched; advertisement.Version=%d, Version=%d", + advertisement.GetVersion(), kBleAdvertisementVersion); + return false; + } + + if (advertisement.GetPcp() != GetPcp()) { + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::IsRecognizedBluetoothEndpoint: Pcp is " + "not matched; advertisement.Pcp=%d, Pcp=%d", + advertisement.GetPcp(), GetPcp()); + return false; + } + + // Check ServiceId for normal advertisement. + // ServiceIdHash is empty for fast advertisement. + if (!advertisement.IsFastAdvertisement()) { + ByteArray expected_service_id_hash = + GenerateHash(service_id, BleAdvertisement::kServiceIdHashLength); + + if (advertisement.GetServiceIdHash() != expected_service_id_hash) { + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::IsRecognizedBleEndpoint: service " + "id hash is " + "not matched; advertisement.service_id_hash=%s, expected=%s", + advertisement.GetServiceIdHash().data(), + expected_service_id_hash.data()); + return false; + } + } + + return true; +} + +void P2pClusterPcpHandler::BlePeripheralDiscoveredHandler( + ClientProxy* client, BlePeripheral& peripheral, + const std::string& service_id, const ByteArray& advertisement_bytes, + bool fast_advertisement) { + RunOnPcpHandlerThread([this, client, &peripheral, service_id, + advertisement_bytes, fast_advertisement]() { + // Make sure we are still discovering before proceeding. + if (!client->IsDiscovering()) { + NEARBY_LOG(INFO, + "Ble scanning handler (FOUND) [client=%p, service_id=%s]: not " + "in discovery mode", + client, service_id.c_str()); + return; + } + + // Parse the BLE advertisement bytes. + BleAdvertisement advertisement(fast_advertisement, advertisement_bytes); + + // Make sure the BLE advertisement points to a valid + // endpoint we're discovering. + if (!IsRecognizedBleEndpoint(service_id, advertisement)) return; + + // Store all the state we need to be able to re-create a BleEndpoint + // in BlePeripheralLostHandler, since that isn't privy to + // the bytes of the ble advertisement itself. + found_ble_endpoints_.emplace( + peripheral.GetName(), + BleEndpointState(advertisement.GetEndpointId(), + advertisement.GetEndpointInfo())); + + // Report the discovered endpoint to the client. + NEARBY_LOGS(INFO) + << "Invoking BasePcpHandler::OnEndpointFound() for Ble service=" + << service_id << "; id=" << advertisement.GetEndpointId() << "; name=" + << absl::BytesToHexString(advertisement.GetEndpointInfo().data()); + OnEndpointFound(client, std::make_shared(BleEndpoint{ + { + advertisement.GetEndpointId(), + advertisement.GetEndpointInfo(), + service_id, + proto::connections::Medium::BLE, + advertisement.GetWebRtcState() + }, + peripheral, + })); + + // Make sure we can connect to this device via Classic Bluetooth. + std::string remote_bluetooth_mac_address = + advertisement.GetBluetoothMacAddress(); + if (remote_bluetooth_mac_address.empty()) { + NEARBY_LOGS(INFO) + << "No Bluetooth Classic MAC address found in advertisement"; + return; + } + + BluetoothDevice remote_bluetooth_device = + bluetooth_medium_.GetRemoteDevice(remote_bluetooth_mac_address); + if (!remote_bluetooth_device.IsValid()) { + NEARBY_LOGS(INFO) << "A valid Bluetooth device could not be derived from " + "the MAC address " + << remote_bluetooth_mac_address; + return; + } + + OnEndpointFound(client, + std::make_shared(BluetoothEndpoint{ + { + advertisement.GetEndpointId(), + advertisement.GetEndpointInfo(), + service_id, + proto::connections::Medium::BLUETOOTH, + advertisement.GetWebRtcState(), + }, + remote_bluetooth_device, + })); + }); +} + +void P2pClusterPcpHandler::BlePeripheralLostHandler( + ClientProxy* client, BlePeripheral& peripheral, + const std::string& service_id) { + std::string peripheral_name = peripheral.GetName(); + NEARBY_LOG(INFO, "Ble: [LOST, SCHED] peripheral_name=%s", + peripheral_name.c_str()); + RunOnPcpHandlerThread([this, client, service_id, &peripheral]() { + // Make sure we are still discovering before proceeding. + if (!client->IsDiscovering()) { + NEARBY_LOG(INFO, + "Ble scanning handler (LOST) [client=%p, service_id=%s]: not " + "in scanning mode", + client, service_id.c_str()); + return; + } + + // Remove this BlePeripheral from found_ble_endpoints_, and + // report the endpoint as lost to the client. + auto item = found_ble_endpoints_.find(peripheral.GetName()); + if (item != found_ble_endpoints_.end()) { + BleEndpointState ble_endpoint_state(item->second); + found_ble_endpoints_.erase(item); + + // Report the discovered endpoint to the client. + NEARBY_LOG(INFO, + "Ble scanning handler (LOST) [client=%p, " + "service_id=%s]: report to client", + client, service_id.c_str()); + OnEndpointLost(client, DiscoveredEndpoint{ + ble_endpoint_state.endpoint_id, + ble_endpoint_state.endpoint_info, + service_id, + proto::connections::Medium::BLE, + WebRtcState::kUndefined, + }); + } + }); +} + +bool P2pClusterPcpHandler::IsRecognizedWifiLanEndpoint( + const std::string& service_id, + const WifiLanServiceInfo& service_info) const { + if (!service_info.IsValid()) { + NEARBY_LOG( + INFO, + "P2pClusterPcpHandler::IsRecognizedWifiLanEndpoint: name is invalid"); + return false; + } + + if (service_info.GetPcp() != GetPcp()) { + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::IsRecognizedWifiLanEndpoint: Pcp is " + "not matched; name.Pcp=%d, Pcp=%d", + service_info.GetPcp(), GetPcp()); + return false; + } + + ByteArray expected_service_id_hash = + GenerateHash(service_id, BluetoothDeviceName::kServiceIdHashLength); + + if (service_info.GetServiceIdHash() != expected_service_id_hash) { + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::IsRecognizedWifiLanEndpoint: service " + "id hash is " + "not matched; name.service_id_hash=%s, expected=%s", + service_info.GetServiceIdHash().data(), + expected_service_id_hash.data()); + return false; + } + + return true; +} + +void P2pClusterPcpHandler::WifiLanServiceDiscoveredHandler( + ClientProxy* client, WifiLanService& service, + const std::string& service_id) { + RunOnPcpHandlerThread([this, client, service_id, &service]() { + // Make sure we are still discovering before proceeding. + if (!client->IsDiscovering()) { + NEARBY_LOG( + INFO, + "WifiLan discovery handler (FOUND) [client=%p, service=%s]: not " + "in discovery mode", + client, service_id.c_str()); + return; + } + + // Parse the WifiLan service name. + WifiLanServiceInfo service_info(service.GetServiceName(), + service.GetTxtRecord(std::string{ + WifiLanServiceInfo::kKeyEndpointInfo})); + + // Make sure the WifiLan service name points to a valid + // endpoint we're discovering. + if (!IsRecognizedWifiLanEndpoint(service_id, service_info)) return; + + // Report the discovered endpoint to the client. + NEARBY_LOG( + INFO, + "Invoking BasePcpHandler::OnEndpointFound() for WifiLan " + "service=%s; id=%s; name=%s", + service_id.c_str(), service_info.GetEndpointId().c_str(), + absl::BytesToHexString(service_info.GetEndpointInfo().data()).c_str()); + OnEndpointFound(client, std::make_shared(WifiLanEndpoint{ + { + service_info.GetEndpointId(), + service_info.GetEndpointInfo(), + service_id, + proto::connections::Medium::WIFI_LAN, + service_info.GetWebRtcState(), + }, + service, + })); + }); +} + +void P2pClusterPcpHandler::WifiLanServiceLostHandler( + ClientProxy* client, WifiLanService& service, + const std::string& service_id) { + std::string service_info_name = service.GetServiceName(); + std::string endpoint_info_name = + service.GetTxtRecord(std::string{WifiLanServiceInfo::kKeyEndpointInfo}); + NEARBY_LOG( + INFO, "WifiLan: [LOST, SCHED] service_info_name=%s, endpoint_info_name=%", + service_info_name.c_str(), endpoint_info_name.c_str()); + RunOnPcpHandlerThread([this, client, service_id, service_info_name, + endpoint_info_name]() { + // Make sure we are still discovering before proceeding. + if (!client->IsDiscovering()) { + NEARBY_LOG( + INFO, + "WifiLan discovery handler (LOST) [client=%p, service=%s]: not " + "in discovery mode", + client, service_id.c_str()); + return; + } + + // Parse the WifiLan service name. + WifiLanServiceInfo service_info(service_info_name, endpoint_info_name); + + // Make sure the WifiLan service name points to a valid + // endpoint we're discovering. + if (!IsRecognizedWifiLanEndpoint(service_id, service_info)) return; + + // Report the discovered endpoint to the client. + NEARBY_LOG( + INFO, + "WifiLan discovery handler (LOST) [client=%p, service_id=%s]: report " + "to client", + client, service_id.c_str()); + OnEndpointLost(client, DiscoveredEndpoint{ + service_info.GetEndpointId(), + service_info.GetEndpointInfo(), + service_id, + proto::connections::Medium::WIFI_LAN, + WebRtcState::kUndefined, + }); + }); +} + +BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartDiscoveryImpl( + ClientProxy* client, const std::string& service_id, + const ConnectionOptions& options) { + // If this is an out-of-band connection, do not start actual discovery, since + // this connection is intended to be completed via InjectEndpointImpl(). + if (options.is_out_of_band_connection) { + return { + .status = {Status::kSuccess}, + .mediums = options.allowed.GetMediums(true) + }; + } + std::vector mediums_started_successfully; - proto::connections::Medium wifi_lan_medium = - StartWifiLanDiscovery(MakePtr(new FoundWifiLanServiceProcessor( - self_, client_proxy, service_id)), - client_proxy, service_id); - if (proto::connections::UNKNOWN_MEDIUM != wifi_lan_medium) { - mediums_started_successfully.push_back(wifi_lan_medium); + if (options.allowed.wifi_lan) { + proto::connections::Medium wifi_lan_medium = StartWifiLanDiscovery( + { + .service_discovered_cb = absl::bind_front( + &P2pClusterPcpHandler::WifiLanServiceDiscoveredHandler, this, + client), + .service_lost_cb = absl::bind_front( + &P2pClusterPcpHandler::WifiLanServiceLostHandler, this, client), + }, + client, service_id); + if (wifi_lan_medium != proto::connections::UNKNOWN_MEDIUM) { + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::StartDiscoveryImpl: WifiLan added"); + mediums_started_successfully.push_back(wifi_lan_medium); + } } - proto::connections::Medium bluetooth_medium = - startBluetoothDiscovery(MakePtr(new FoundBluetoothAdvertisementProcessor( - self_, client_proxy, service_id)), - client_proxy, service_id); - if (proto::connections::UNKNOWN_MEDIUM != bluetooth_medium) { - mediums_started_successfully.push_back(bluetooth_medium); + if (options.allowed.bluetooth) { + proto::connections::Medium bluetooth_medium = StartBluetoothDiscovery( + { + .device_discovered_cb = absl::bind_front( + &P2pClusterPcpHandler::BluetoothDeviceDiscoveredHandler, this, + client, service_id), + .device_name_changed_cb = absl::bind_front( + &P2pClusterPcpHandler::BluetoothDeviceDiscoveredHandler, this, + client, service_id), + .device_lost_cb = absl::bind_front( + &P2pClusterPcpHandler::BluetoothDeviceLostHandler, this, client, + service_id), + }, + client, service_id); + if (bluetooth_medium != proto::connections::UNKNOWN_MEDIUM) { + NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartDiscoveryImpl: BT added"); + mediums_started_successfully.push_back(bluetooth_medium); + } } - proto::connections::Medium ble_medium = startBleDiscovery( - MakePtr(new FoundBleAdvertisementProcessor(self_, client_proxy)), - client_proxy, service_id); - if (proto::connections::UNKNOWN_MEDIUM != ble_medium) { - mediums_started_successfully.push_back(ble_medium); + if (options.allowed.ble) { + proto::connections::Medium ble_medium = StartBleScanning( + { + .peripheral_discovered_cb = absl::bind_front( + &P2pClusterPcpHandler::BlePeripheralDiscoveredHandler, this, + client), + .peripheral_lost_cb = absl::bind_front( + &P2pClusterPcpHandler::BlePeripheralLostHandler, this, client), + }, + client, service_id, options.fast_advertisement_service_uuid); + if (ble_medium != proto::connections::UNKNOWN_MEDIUM) { + NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartDiscoveryImpl: Ble added"); + mediums_started_successfully.push_back(ble_medium); + } } if (mediums_started_successfully.empty()) { - // TODO(tracyzhou): Add logging. - return BasePCPHandler::StartOperationResult::error( - Status::BLUETOOTH_ERROR); + NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartDiscoveryImpl: nothing added"); + return { + .status = {Status::kBluetoothError}, + }; } - return BasePCPHandler::StartOperationResult::success( - mediums_started_successfully); + return { + .status = {Status::kSuccess}, + .mediums = std::move(mediums_started_successfully), + }; } -template -Status::Value P2PClusterPCPHandler::stopDiscoveryImpl( - Ptr> client_proxy) { - medium_manager_->stopBleScanning(client_proxy->getDiscoveryServiceId()); - medium_manager_->stopScanningForBluetoothDevices(); - return Status::SUCCESS; +Status P2pClusterPcpHandler::StopDiscoveryImpl(ClientProxy* client) { + wifi_lan_medium_.StopDiscovery(client->GetDiscoveryServiceId()); + bluetooth_medium_.StopDiscovery(); + ble_medium_.StopScanning(client->GetDiscoveryServiceId()); + return {Status::kSuccess}; } -template -typename BasePCPHandler::ConnectImplResult -P2PClusterPCPHandler::connectImpl( - Ptr> client_proxy, - Ptr::DiscoveredEndpoint> endpoint) { - Ptr wifi_lan_endpoint = - DowncastPtr(endpoint); - if (!wifi_lan_endpoint.isNull()) { - return WifiLanConnectImpl(client_proxy, wifi_lan_endpoint); +Status P2pClusterPcpHandler::InjectEndpointImpl( + ClientProxy* client, + const std::string& service_id, + const OutOfBandConnectionMetadata& metadata) { + NEARBY_LOG(INFO, "InjectEndpoint"); + // Bluetooth is the only supported out-of-band connection medium. + if (metadata.medium != Medium::BLUETOOTH) { + NEARBY_LOG(WARNING, "StartDiscoveryImpl: Only Bluetooth is supported"); + return {Status::kError}; } - Ptr bluetooth_endpoint = - DowncastPtr(endpoint); - if (!bluetooth_endpoint.isNull()) { - return bluetoothConnectImpl(client_proxy, bluetooth_endpoint); + std::string remote_bluetooth_mac_address = + BluetoothUtils::ToString(metadata.remote_bluetooth_mac_address); + if (remote_bluetooth_mac_address.empty()) { + NEARBY_LOG(WARNING, "StartDiscoveryImpl: Missing Bluetooth MAC"); + return {Status::kError}; } - Ptr ble_endpoint = DowncastPtr(endpoint); - if (!ble_endpoint.isNull()) { - return bleConnectImpl(client_proxy, ble_endpoint); + auto remote_bluetooth_device = + GetRemoteBluetoothDevice(remote_bluetooth_mac_address); + if (!remote_bluetooth_device.IsValid()) { + NEARBY_LOG(WARNING, "StartDiscoveryImpl: Invalid Bluetooth MAC"); + return {Status::kError}; } - return typename BasePCPHandler::ConnectImplResult( - proto::connections::Medium::UNKNOWN_MEDIUM, Status::ERROR); + BluetoothDeviceDiscoveredHandler(client, service_id, remote_bluetooth_device); + return {Status::kSuccess}; } -/////////////////// START IMPLEMENTATIONS FOR NESTED CLASSES /////////////////// - -///////// P2PClusterPCPHandler::IncomingBluetoothConnectionProcessor ////////// -template -P2PClusterPCPHandler::IncomingBluetoothConnectionProcessor:: - IncomingBluetoothConnectionProcessor( - Ptr> pcp_handler, - Ptr> client_proxy, - const string& local_endpoint_name) - : pcp_handler_(pcp_handler), - client_proxy_(client_proxy), - local_endpoint_name_(local_endpoint_name) {} - -template -void P2PClusterPCPHandler::IncomingBluetoothConnectionProcessor:: - onIncomingBluetoothConnection(Ptr bluetooth_socket) { - pcp_handler_->runOnPCPHandlerThread( - MakePtr(new OnIncomingBluetoothConnectionRunnable( - pcp_handler_, client_proxy_, bluetooth_socket))); -} - -template -P2PClusterPCPHandler::IncomingBluetoothConnectionProcessor:: - OnIncomingBluetoothConnectionRunnable:: - OnIncomingBluetoothConnectionRunnable( - Ptr> pcp_handler, - Ptr> client_proxy, - Ptr bluetooth_socket) - : pcp_handler_(pcp_handler), - client_proxy_(client_proxy), - bluetooth_socket_(bluetooth_socket) {} - -template -void P2PClusterPCPHandler::IncomingBluetoothConnectionProcessor:: - OnIncomingBluetoothConnectionRunnable::run() { - string remote_device_name = bluetooth_socket_->getRemoteDevice()->getName(); - ScopedPtr> scoped_bluetooth_endpoint_channel( - pcp_handler_->endpoint_channel_manager_ - ->createIncomingBluetoothEndpointChannel(remote_device_name, - bluetooth_socket_)); - if (!scoped_bluetooth_endpoint_channel.isNull()) { - // TODO(tracyzhou): Add logging. - } else { - Exception::Value exception = bluetooth_socket_->close(); - bluetooth_socket_.destroy(); - if (Exception::NONE != exception) { - if (Exception::IO == exception) { - // TODO(tracyzhou): Add logging. +BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::ConnectImpl( + ClientProxy* client, BasePcpHandler::DiscoveredEndpoint* endpoint) { + if (!endpoint) { + return BasePcpHandler::ConnectImplResult{ + .status = {Status::kError}, + }; + } + switch (endpoint->medium) { + case proto::connections::Medium::BLUETOOTH: { + auto* bluetooth_endpoint = down_cast(endpoint); + if (bluetooth_endpoint) { + return BluetoothConnectImpl(client, bluetooth_endpoint); } + break; } - } - pcp_handler_->onIncomingConnection( - client_proxy_, remote_device_name, - scoped_bluetooth_endpoint_channel.release(), - proto::connections::Medium::BLUETOOTH); -} - -//////////// P2PClusterPCPHandler::IncomingBleConnectionProcessor ///////////// -template -P2PClusterPCPHandler::IncomingBleConnectionProcessor:: - IncomingBleConnectionProcessor( - Ptr> pcp_handler, - Ptr> client_proxy, - const string& local_endpoint_name) - : pcp_handler_(pcp_handler), - client_proxy_(client_proxy), - local_endpoint_name_(local_endpoint_name) {} - -template -void P2PClusterPCPHandler::IncomingBleConnectionProcessor:: - onIncomingBleConnection(Ptr ble_socket, - const string& service_id) { - pcp_handler_->runOnPCPHandlerThread( - MakePtr(new OnIncomingBleConnectionRunnable(pcp_handler_, client_proxy_, - ble_socket))); -} - -template -P2PClusterPCPHandler::IncomingBleConnectionProcessor:: - OnIncomingBleConnectionRunnable::OnIncomingBleConnectionRunnable( - Ptr> pcp_handler, - Ptr> client_proxy, Ptr ble_socket) - : pcp_handler_(pcp_handler), - client_proxy_(client_proxy), - ble_socket_(ble_socket) {} - -template -void P2PClusterPCPHandler::IncomingBleConnectionProcessor:: - OnIncomingBleConnectionRunnable::run() { - string remote_device_name = - ble_socket_->getRemotePeripheral()->getBluetoothDevice()->getName(); - ScopedPtr> scoped_ble_endpoint_channel( - pcp_handler_->endpoint_channel_manager_->createIncomingBLEEndpointChannel( - remote_device_name, ble_socket_)); - if (!scoped_ble_endpoint_channel.isNull()) { - // TODO(ahlee): Add logging. - } else { - Exception::Value exception = ble_socket_->close(); - ble_socket_.destroy(); - if (Exception::NONE != exception) { - if (Exception::IO == exception) { - // TODO(ahlee): Add logging. + case proto::connections::Medium::BLE: { + auto* ble_endpoint = down_cast(endpoint); + if (ble_endpoint) { + return BleConnectImpl(client, ble_endpoint); } + break; } - } - pcp_handler_->onIncomingConnection(client_proxy_, remote_device_name, - scoped_ble_endpoint_channel.release(), - proto::connections::Medium::BLE); -} - -//////////// P2PClusterPCPHandler::IncomingWifiLanConnectionProcessor ///////// -template -P2PClusterPCPHandler::IncomingWifiLanConnectionProcessor:: - IncomingWifiLanConnectionProcessor( - Ptr> pcp_handler, - Ptr> client_proxy, - absl::string_view local_endpoint_name) - : pcp_handler_(pcp_handler), - client_proxy_(client_proxy), - local_endpoint_name_(local_endpoint_name) {} - -template -void P2PClusterPCPHandler::IncomingWifiLanConnectionProcessor:: - OnIncomingWifiLanConnection(Ptr wifi_lan_socket) { - pcp_handler_->runOnPCPHandlerThread( - MakePtr(new OnIncomingWifiLanConnectionRunnable( - pcp_handler_, client_proxy_, wifi_lan_socket))); -} - -template -P2PClusterPCPHandler::IncomingWifiLanConnectionProcessor:: - OnIncomingWifiLanConnectionRunnable::OnIncomingWifiLanConnectionRunnable( - Ptr> pcp_handler, - Ptr> client_proxy, - Ptr wifi_lan_socket) - : pcp_handler_(pcp_handler), - client_proxy_(client_proxy), - wifi_lan_socket_(wifi_lan_socket) {} - -template -void P2PClusterPCPHandler::IncomingWifiLanConnectionProcessor:: - OnIncomingWifiLanConnectionRunnable::run() { - string remote_service_name = - wifi_lan_socket_->GetRemoteWifiLanService()->GetName(); - ScopedPtr> scoped_wifi_lan_endpoint_channel( - pcp_handler_->endpoint_channel_manager_ - ->CreateIncomingWifiLanEndpointChannel(remote_service_name, - wifi_lan_socket_)); - if (!scoped_wifi_lan_endpoint_channel.isNull()) { - // TODO(b/149806065): Add logging. - } else { - Exception::Value exception = wifi_lan_socket_->Close(); - wifi_lan_socket_.destroy(); - if (Exception::NONE != exception) { - if (Exception::IO == exception) { - // TODO(b/149806065): Add logging. + case proto::connections::Medium::WIFI_LAN: { + auto* wifi_lan_endpoint = down_cast(endpoint); + if (wifi_lan_endpoint) { + return WifiLanConnectImpl(client, wifi_lan_endpoint); } + break; } + case proto::connections::Medium::WEB_RTC: { + auto* webrtc_endpoint = down_cast(endpoint); + if (webrtc_endpoint) { + return WebRtcConnectImpl(client, webrtc_endpoint); + } + break; + } + default: + break; } - pcp_handler_->onIncomingConnection(client_proxy_, remote_service_name, - scoped_wifi_lan_endpoint_channel.release(), - proto::connections::Medium::WIFI_LAN); + + return BasePcpHandler::ConnectImplResult{ + .status = {Status::kError}, + }; } -///////// P2PClusterPCPHandler::FoundBluetoothAdvertisementProcessor ////////// -template -P2PClusterPCPHandler::FoundBluetoothAdvertisementProcessor:: - FoundBluetoothAdvertisementProcessor( - Ptr> pcp_handler, - Ptr> client_proxy, const string& service_id) - : pcp_handler_(pcp_handler), - client_proxy_(client_proxy), - service_id_(service_id), - expected_service_id_hash_(generateHash( - service_id, BluetoothDeviceName::kServiceIdHashLength)) {} - -template -void P2PClusterPCPHandler::FoundBluetoothAdvertisementProcessor:: - onFoundBluetoothDevice(Ptr bluetooth_device) { - pcp_handler_->runOnPCPHandlerThread( - MakePtr(new OnFoundBluetoothDeviceRunnable(pcp_handler_, client_proxy_, - self_, service_id_, - bluetooth_device))); -} - -template -void P2PClusterPCPHandler::FoundBluetoothAdvertisementProcessor:: - onLostBluetoothDevice(Ptr bluetooth_device) { - pcp_handler_->runOnPCPHandlerThread(MakePtr(new OnLostBluetoothDeviceRunnable( - pcp_handler_, client_proxy_, self_, service_id_, - bluetooth_device))); -} - -template -bool P2PClusterPCPHandler::FoundBluetoothAdvertisementProcessor:: - isRecognizedBluetoothEndpoint( - const string& found_bluetooth_device_name, - Ptr bluetooth_device_name) { - if (bluetooth_device_name.isNull()) { - // TODO(tracyzhou): Add logging. - return false; - } - - if (bluetooth_device_name->getPCP() != pcp_handler_->getPCP()) { - // TODO(tracyzhou): Add logging. - return false; - } - - if (*(bluetooth_device_name->getServiceIdHash()) != - *(expected_service_id_hash_.get())) { - // TODO(tracyzhou): Add logging. - return false; - } - - return true; -} - -template -P2PClusterPCPHandler::FoundBluetoothAdvertisementProcessor:: - OnFoundBluetoothDeviceRunnable::OnFoundBluetoothDeviceRunnable( - Ptr> pcp_handler, - Ptr> client_proxy, - Ptr - found_bluetooth_advertisement_processor, - const string& service_id, Ptr bluetooth_device) - : pcp_handler_(pcp_handler), - client_proxy_(client_proxy), - found_bluetooth_advertisement_processor_( - found_bluetooth_advertisement_processor), - service_id_(service_id), - bluetooth_device_(bluetooth_device) {} - -template -void P2PClusterPCPHandler::FoundBluetoothAdvertisementProcessor:: - OnFoundBluetoothDeviceRunnable::run() { - // Make sure we are still discovering before proceeding. - if (!client_proxy_->isDiscovering()) { - // TODO(tracyzhou): Add logging. - return; - } - - // Parse the Bluetooth device name. - ScopedPtr> bluetooth_device_name( - BluetoothDeviceName::fromString(bluetooth_device_->getName())); - - // Make sure the Bluetooth device name points to a valid endpoint we're - // discovering. - if (!found_bluetooth_advertisement_processor_->isRecognizedBluetoothEndpoint( - bluetooth_device_->getName(), bluetooth_device_name.get())) { - return; - } - - // Report the discovered endpoint to the client. - // TODO(tracyzhou): Add logging. - pcp_handler_->onEndpointFound( - client_proxy_, - MakePtr(new BluetoothEndpoint( - bluetooth_device_.release(), bluetooth_device_name->getEndpointId(), - bluetooth_device_name->getEndpointName(), service_id_))); -} - -template -P2PClusterPCPHandler::FoundBluetoothAdvertisementProcessor:: - OnLostBluetoothDeviceRunnable::OnLostBluetoothDeviceRunnable( - Ptr> pcp_handler, - Ptr> client_proxy, - Ptr - found_bluetooth_advertisement_processor, - const string& service_id, Ptr bluetooth_device) - : pcp_handler_(pcp_handler), - client_proxy_(client_proxy), - found_bluetooth_advertisement_processor_( - found_bluetooth_advertisement_processor), - service_id_(service_id), - bluetooth_device_(bluetooth_device) {} - -template -void P2PClusterPCPHandler::FoundBluetoothAdvertisementProcessor:: - OnLostBluetoothDeviceRunnable::run() { - // Make sure we are still discovering before proceeding. - if (!client_proxy_->isDiscovering()) { - // TODO(tracyzhou): Add logging. - return; - } - - // Parse the Bluetooth device name. - ScopedPtr> bluetooth_device_name( - BluetoothDeviceName::fromString(bluetooth_device_->getName())); - - // Make sure the Bluetooth device name points to a valid endpoint we're - // discovering. - if (!found_bluetooth_advertisement_processor_->isRecognizedBluetoothEndpoint( - bluetooth_device_->getName(), bluetooth_device_name.get())) { - return; - } - - // Report the endpoint as lost to the client. - // TODO(tracyzhou): Add logging. - pcp_handler_->onEndpointLost( - client_proxy_, - MakePtr(new BluetoothEndpoint( - bluetooth_device_.release(), bluetooth_device_name->getEndpointId(), - bluetooth_device_name->getEndpointName(), service_id_))); -} - -//////////// P2PClusterPCPHandler::FoundBleAdvertisementProcessor ///////////// -template -P2PClusterPCPHandler::FoundBleAdvertisementProcessor:: - FoundBleAdvertisementProcessor( - Ptr> pcp_handler, - Ptr> client_proxy) - : pcp_handler_(pcp_handler), client_proxy_(client_proxy) {} - -template -void P2PClusterPCPHandler::FoundBleAdvertisementProcessor:: - onFoundBlePeripheral(Ptr ble_peripheral, - const string& service_id, - ConstPtr advertisement_bytes) { - pcp_handler_->runOnPCPHandlerThread(MakePtr(new OnFoundBlePeripheralRunnable( - pcp_handler_, client_proxy_, self_, service_id, ble_peripheral, - advertisement_bytes))); -} - -template -P2PClusterPCPHandler::FoundBleAdvertisementProcessor:: - OnFoundBlePeripheralRunnable::OnFoundBlePeripheralRunnable( - Ptr> pcp_handler, - Ptr> client_proxy, - Ptr found_ble_advertisement_processor, - const string& service_id, Ptr ble_peripheral, - ConstPtr advertisement_bytes) - : pcp_handler_(pcp_handler), - client_proxy_(client_proxy), - found_ble_advertisement_processor_(found_ble_advertisement_processor), - service_id_(service_id), - ble_peripheral_(ble_peripheral), - advertisement_bytes_(advertisement_bytes), - expected_service_id_hash_( - generateHash(service_id, BLEAdvertisement::kServiceIdHashLength)) {} - -template -void P2PClusterPCPHandler::FoundBleAdvertisementProcessor:: - OnFoundBlePeripheralRunnable::run() { - // Make sure we are still discovering before proceeding. - if (!client_proxy_->isDiscovering()) { - // TODO(ahlee): logger.atWarning().log("Skipping discovery of - // BLEAdvertisement header %s because we are no longer discovering.", - // bytesToString(advertisementBytes)); - return; - } - - ScopedPtr> scoped_ble_advertisement( - BLEAdvertisement::fromBytes(advertisement_bytes_.get())); - if (scoped_ble_advertisement.isNull()) { - // TODO(ahlee): logger.atVerbose().log("%s doesn't conform to the - // BLEAdvertisement format, discarding.", - // bytesToSTring(advertisementBytes)); - return; - } - - if (scoped_ble_advertisement->getVersion() != BLEAdvertisement::Version::V1) { - // TODO(ahlee): logging - return; - } - - if (scoped_ble_advertisement->getPCP() != pcp_handler_->getPCP()) { - // TODO(ahlee): Add logging - return; - } - - if (*(scoped_ble_advertisement->getServiceIdHash()) != - *(expected_service_id_hash_.get())) { - // TODO(ahlee): Add logging - return; - } - - // TODO(ahlee): Add logging. - - // Store all the state we need to be able to re-create a BLEEndpoint in - // OnLostBlePeripheralRunnable::run(), since that isn't privy to the bytes of - // the BLE advertisement itself. - found_ble_advertisement_processor_->found_ble_endpoints_.insert( - std::make_pair( - getBlePeripheralId(ble_peripheral_.get()), - BLEEndpointState(scoped_ble_advertisement->getEndpointId(), - scoped_ble_advertisement->getEndpointName()))); - - pcp_handler_->onEndpointFound( - client_proxy_, - MakePtr(new BLEEndpoint( - ble_peripheral_.release(), scoped_ble_advertisement->getEndpointId(), - scoped_ble_advertisement->getEndpointName(), service_id_))); - - // TODO(b/75047971): Add functionality to connect over Bluetooth. -} - -template -void P2PClusterPCPHandler::FoundBleAdvertisementProcessor:: - onLostBlePeripheral(Ptr ble_peripheral, - const string& service_id) { - pcp_handler_->runOnPCPHandlerThread(MakePtr(new OnLostBlePeripheralRunnable( - pcp_handler_, client_proxy_, self_, service_id, ble_peripheral))); -} - -template -P2PClusterPCPHandler::FoundBleAdvertisementProcessor:: - OnLostBlePeripheralRunnable::OnLostBlePeripheralRunnable( - Ptr> pcp_handler, - Ptr> client_proxy, - Ptr found_ble_advertisement_processor, - const string& service_id, Ptr ble_peripheral) - : pcp_handler_(pcp_handler), - client_proxy_(client_proxy), - found_ble_advertisement_processor_(found_ble_advertisement_processor), - service_id_(service_id), - ble_peripheral_(ble_peripheral) {} - -template -void P2PClusterPCPHandler::FoundBleAdvertisementProcessor:: - OnLostBlePeripheralRunnable::run() { - // Make sure we are still discovering before proceeding. - if (!client_proxy_->isDiscovering()) { - // TODO(reznor): logger.atWarning().log("Ignoring lost BlePeripheral %s - // because we are no longer discovering.", blePeripheral); - return; - } - - // Remove this BLEPeripheral from - // found_ble_advertisement_processor_->found_ble_endpoints_, and report the - // endpoint as lost to the client. - typename FoundBLEEndpointsMap::iterator it = - found_ble_advertisement_processor_->found_ble_endpoints_.find( - getBlePeripheralId(ble_peripheral_.get())); - if (it != found_ble_advertisement_processor_->found_ble_endpoints_.end()) { - // TODO(reznor): logger.atDebug().log("Lost BlePeripheral %s (with - // EndpointId %s and EndpointName %s)", blePeripheral, - // bleEndpoint.getEndpointId(), bleEndpoint.getEndpointName()); - - // Make a copy since it->second will get destroyed once we call erase() - // below. - BLEEndpointState ble_endpoint_state(it->second); - found_ble_advertisement_processor_->found_ble_endpoints_.erase(it); - - pcp_handler_->onEndpointLost( - client_proxy_, - MakePtr(new BLEEndpoint( - ble_peripheral_.release(), ble_endpoint_state.endpoint_id, - ble_endpoint_state.endpoint_name, service_id_))); - } -} - -////////// P2PClusterPCPHandler::FoundWifiLanServiceProcessor /////////// -template -P2PClusterPCPHandler::FoundWifiLanServiceProcessor:: - FoundWifiLanServiceProcessor( - Ptr> pcp_handler, - Ptr> client_proxy, absl::string_view service_id) - : pcp_handler_(pcp_handler), - client_proxy_(client_proxy), - service_id_(service_id), - expected_service_id_hash_(generateHash( - string(service_id), WifiLanServiceInfo::kServiceIdHashLength)) {} - -template -void P2PClusterPCPHandler::FoundWifiLanServiceProcessor:: - OnFoundWifiLanService(Ptr wifi_lan_service) { - pcp_handler_->runOnPCPHandlerThread(MakePtr(new OnFoundWifiLanServiceRunnable( - pcp_handler_, client_proxy_, self_, service_id_, wifi_lan_service))); -} - -template -void P2PClusterPCPHandler::FoundWifiLanServiceProcessor:: - OnLostWifiLanService(Ptr wifi_lan_service) { - pcp_handler_->runOnPCPHandlerThread(MakePtr(new OnLostWifiLanServiceRunnable( - pcp_handler_, client_proxy_, self_, service_id_, wifi_lan_service))); -} - -template -bool P2PClusterPCPHandler::FoundWifiLanServiceProcessor:: - IsRecognizedWifiLanEndpoint(Ptr wifi_lan_service_info) { - if (wifi_lan_service_info.isNull()) { - return false; - } - - if (wifi_lan_service_info->GetPcp() != pcp_handler_->getPCP()) { - return false; - } - - if (*(wifi_lan_service_info->GetServiceIdHash()) != - *(expected_service_id_hash_.get())) { - return false; - } - - return true; -} - -template -P2PClusterPCPHandler::FoundWifiLanServiceProcessor:: - OnFoundWifiLanServiceRunnable::OnFoundWifiLanServiceRunnable( - Ptr> pcp_handler, - Ptr> client_proxy, - Ptr found_wifi_lan_service_processor, - absl::string_view service_id, Ptr wifi_lan_service) - : pcp_handler_(pcp_handler), - client_proxy_(client_proxy), - found_wifi_lan_service_processor_(found_wifi_lan_service_processor), - service_id_(service_id), - wifi_lan_service_(wifi_lan_service), - expected_service_id_hash_(generateHash( - string(service_id), WifiLanServiceInfo::kServiceIdHashLength)) {} - -template -void P2PClusterPCPHandler::FoundWifiLanServiceProcessor:: - OnFoundWifiLanServiceRunnable::run() { - // Make sure we are still discovering before proceeding. - if (!client_proxy_->isDiscovering()) { - return; - } - - // Parse the WifiLan service name. - ScopedPtr> wifi_lan_service_info( - WifiLanServiceInfo::FromString(wifi_lan_service_->GetName())); - - // Make sure the WifiLan service name points to a valid endpoint we're - // discovering. - if (!found_wifi_lan_service_processor_->IsRecognizedWifiLanEndpoint( - wifi_lan_service_info.get())) { - return; - } - - // Report the discovered endpoint to the client. - pcp_handler_->onEndpointFound( - client_proxy_, - MakePtr(new WifiLanEndpoint( - wifi_lan_service_.release(), - wifi_lan_service_info->GetEndpointId(), - wifi_lan_service_info->GetEndpointName(), service_id_))); -} - -template -P2PClusterPCPHandler::FoundWifiLanServiceProcessor:: - OnLostWifiLanServiceRunnable::OnLostWifiLanServiceRunnable( - Ptr> pcp_handler, - Ptr> client_proxy, - Ptr found_wifi_lan_service_processor, - absl::string_view service_id, Ptr wifi_lan_service) - : pcp_handler_(pcp_handler), - client_proxy_(client_proxy), - found_wifi_lan_service_processor_(found_wifi_lan_service_processor), - service_id_(service_id), - wifi_lan_service_(wifi_lan_service.operator->()) {} - -template -void P2PClusterPCPHandler::FoundWifiLanServiceProcessor:: - OnLostWifiLanServiceRunnable::run() { - // Make sure we are still discovering before proceeding. - if (!client_proxy_->isDiscovering()) { - // TODO(b/149806065): Add logging. - return; - } - - // Parse the WifiLan service name. - ScopedPtr> wifi_lan_service_info( - WifiLanServiceInfo::FromString(wifi_lan_service_->GetName())); - - // Make sure the WifiLan service name points to a valid endpoint we're - // discovering. - if (!found_wifi_lan_service_processor_->IsRecognizedWifiLanEndpoint( - wifi_lan_service_info.get())) { - return; - } - - // Report the endpoint as lost to the client. - // TODO(b/149806065): Add logging. - pcp_handler_->onEndpointLost( - client_proxy_, - MakePtr(new WifiLanEndpoint( - Ptr(wifi_lan_service_.release()), - wifi_lan_service_info->GetEndpointId(), - wifi_lan_service_info->GetEndpointName(), service_id_))); -} - -//////////////////// END IMPLEMENTATIONS FOR NESTED CLASSES //////////////////// - -template -proto::connections::Medium -P2PClusterPCPHandler::startBluetoothAdvertising( - Ptr> client_proxy, const string& service_id, - ConstPtr service_id_hash, const string& local_endpoint_id, - const string& local_endpoint_name) { +proto::connections::Medium P2pClusterPcpHandler::StartBluetoothAdvertising( + ClientProxy* client, const std::string& service_id, + const ByteArray& service_id_hash, const std::string& local_endpoint_id, + const ByteArray& local_endpoint_info, WebRtcState web_rtc_state) { // Start listening for connections before advertising in case a connection // request comes in very quickly. - if (!medium_manager_->isListeningForIncomingBluetoothConnections( - service_id)) { - if (!medium_manager_->startListeningForIncomingBluetoothConnections( - service_id, - MakePtr(new IncomingBluetoothConnectionProcessor( - self_, client_proxy, local_endpoint_name)))) { - // TODO(tracyzhou): Add logging. - return proto::connections::UNKNOWN_MEDIUM; - } - - // TODO(tracyzhou): Add logging. + NEARBY_LOG( + INFO, + "P2pClusterPcpHandler::StartBluetoothAdvertising: service=%s: start", + service_id.c_str()); + if (bluetooth_medium_.IsAcceptingConnections(service_id)) { + NEARBY_LOG(INFO, "BT is already accepting connections for service=%s", + service_id.c_str()); + return proto::connections::UNKNOWN_MEDIUM; } + NEARBY_LOG( + INFO, + "P2pClusterPcpHandler::StartBluetoothAdvertising: service=%s: invoking", + service_id.c_str()); + if (!bluetooth_radio_.Enable() || + !bluetooth_medium_.StartAcceptingConnections( + service_id, {.accepted_cb = [this, client, local_endpoint_info]( + BluetoothSocket socket) { + if (!socket.IsValid()) { + NEARBY_LOG(ERROR, "Invalid socket in accept callback: name=%s", + std::string(local_endpoint_info).c_str()); + return; + } + RunOnPcpHandlerThread([this, client, local_endpoint_info, + socket = std::move(socket)]() mutable { + std::string remote_device_name = + socket.GetRemoteDevice().GetName(); + auto channel = absl::make_unique( + remote_device_name, socket); + ByteArray remote_device_info{remote_device_name}; + + OnIncomingConnection(client, remote_device_info, + std::move(channel), + proto::connections::Medium::BLUETOOTH); + }); + }})) { + NEARBY_LOG(INFO, "BT failed to start accepting connections for service=%s", + service_id.c_str()); + return proto::connections::UNKNOWN_MEDIUM; + } + + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::StartBluetoothAdvertising: service=%s: " + "make name; id=%s, hash=%s, name=%s", + service_id.c_str(), local_endpoint_id.c_str(), + absl::BytesToHexString(service_id_hash.data()).c_str(), + absl::BytesToHexString(local_endpoint_info.data()).c_str()); // Generate a BluetoothDeviceName with which to become Bluetooth discoverable. - const string bluetooth_device_name = BluetoothDeviceName::asString( - kBluetoothDeviceNameVersion, getPCP(), local_endpoint_id, service_id_hash, - local_endpoint_name); - if (bluetooth_device_name.empty()) { - // TODO(tracyzhou): Add logging. - medium_manager_->stopListeningForIncomingBluetoothConnections(service_id); + // TODO(b/169550050): Implement UWBAddress. + std::string device_name(BluetoothDeviceName( + kBluetoothDeviceNameVersion, GetPcp(), local_endpoint_id, service_id_hash, + local_endpoint_info, ByteArray{}, web_rtc_state)); + if (device_name.empty()) { + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::StartBluetoothAdvertising: generate " + "BluetoothDeviceName failed"); + bluetooth_medium_.StopAcceptingConnections(service_id); return proto::connections::UNKNOWN_MEDIUM; } else { - // TODO(tracyzhou): Add logging. + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::StartBluetoothAdvertising: generate " + "BluetoothDeviceName succeeded; device_name=%s", + device_name.c_str()); } + NEARBY_LOG( + INFO, + "P2pClusterPcpHandler::StartBluetoothAdvertising: service=%s: come up", + service_id.c_str()); // Become Bluetooth discoverable. - if (!medium_manager_->turnOnBluetoothDiscoverability(bluetooth_device_name)) { - // TODO(tracyzhou): Add logging. - medium_manager_->stopListeningForIncomingBluetoothConnections(service_id); + if (!bluetooth_medium_.TurnOnDiscoverability(device_name)) { + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::StartBluetoothAdvertising: failed to " + "turn on discoverability, device_name=%s", + device_name.c_str()); + bluetooth_medium_.StopAcceptingConnections(service_id); return proto::connections::UNKNOWN_MEDIUM; } else { - // TODO(tracyzhou): Add logging. + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::StartBluetoothAdvertising: succeeded to " + "turn on discoverability, device_name=%s", + device_name.c_str()); } + NEARBY_LOG( + INFO, "P2pClusterPcpHandler::StartBluetoothAdvertising: service=%s: done", + service_id.c_str()); return proto::connections::BLUETOOTH; } -template -proto::connections::Medium -P2PClusterPCPHandler::startBluetoothDiscovery( - Ptr processor, - Ptr> client_proxy, const string& service_id) { - if (!medium_manager_->startScanningForBluetoothDevices(processor)) { - // TODO(tracyzhou): Add logging. - return proto::connections::UNKNOWN_MEDIUM; +proto::connections::Medium P2pClusterPcpHandler::StartBluetoothDiscovery( + BluetoothDiscoveredDeviceCallback callback, ClientProxy* client, + const std::string& service_id) { + if (bluetooth_radio_.Enable() && + bluetooth_medium_.StartDiscovery(std::move(callback))) { + NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartBluetoothDiscovery: ok"); + return proto::connections::BLUETOOTH; } else { - // TODO(tracyzhou): Add logging. + NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartBluetoothDiscovery: failed"); + return proto::connections::UNKNOWN_MEDIUM; } - - return proto::connections::BLUETOOTH; } -template -proto::connections::Medium P2PClusterPCPHandler::startBleAdvertising( - Ptr> client_proxy, const string& service_id, - ConstPtr service_id_hash, const string& local_endpoint_id, - const string& local_endpoint_name) { +BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BluetoothConnectImpl( + ClientProxy* client, BluetoothEndpoint* endpoint) { + BluetoothDevice& device = endpoint->bluetooth_device; + + BluetoothSocket bluetooth_socket = + bluetooth_medium_.Connect(device, endpoint->service_id); + if (!bluetooth_socket.IsValid()) { + return BasePcpHandler::ConnectImplResult{ + .status = {Status::kBluetoothError}, + }; + } + + auto channel = absl::make_unique( + endpoint->endpoint_id, bluetooth_socket); + + return BasePcpHandler::ConnectImplResult{ + .medium = proto::connections::Medium::BLUETOOTH, + .status = {Status::kSuccess}, + .endpoint_channel = std::move(channel), + }; +} + +proto::connections::Medium P2pClusterPcpHandler::StartBleAdvertising( + ClientProxy* client, const std::string& service_id, + const std::string& local_endpoint_id, const ByteArray& local_endpoint_info, + const ConnectionOptions& options, WebRtcState web_rtc_state) { + bool fast_advertisement = !options.fast_advertisement_service_uuid.empty(); + PowerLevel power_level = + options.low_power ? PowerLevel::kLowPower : PowerLevel::kHighPower; + // Start listening for connections before advertising in case a connection - // request comes in very quickly. - if (!medium_manager_->isListeningForIncomingBleConnections(service_id)) { - if (!medium_manager_->startListeningForIncomingBleConnections( - service_id, - MakePtr(new IncomingBleConnectionProcessor( - self_, client_proxy, local_endpoint_name)))) { - // TODO(ahlee): logger.atWarning().log("In startBleAdvertising(%s), client - // %d failed to start listening for incoming BLE connections to ServiceId - // %s", local_endpoint_name, clientProxy.getClientId(), service_id); + // request comes in very quickly. BLE allows connecting over BLE itself, as + // well as advertising the Bluetooth MAC address to allow connecting over + // Bluetooth Classic. + NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleAdvertising: service_id=" + << service_id << ": start"; + if (!ble_medium_.IsAcceptingConnections(service_id)) { + if (!bluetooth_radio_.Enable() || + !ble_medium_.StartAcceptingConnections( + service_id, {.accepted_cb = [this, client, local_endpoint_info]( + BleSocket socket, + const std::string& service_id) { + if (!socket.IsValid()) { + NEARBY_LOG(INFO, "Invalid socket in accept callback: name=%s", + std::string(local_endpoint_info).c_str()); + return; + } + RunOnPcpHandlerThread([this, client, local_endpoint_info, + service_id, + socket = std::move(socket)]() mutable { + std::string remote_peripheral_name = + socket.GetRemotePeripheral().GetName(); + auto channel = absl::make_unique( + remote_peripheral_name, socket); + ByteArray remote_peripheral_info = + socket.GetRemotePeripheral().GetAdvertisementBytes( + service_id); + + OnIncomingConnection(client, remote_peripheral_info, + std::move(channel), + proto::connections::Medium::BLE); + }); + }})) { + NEARBY_LOGS(INFO) + << "Ble failed to start accepting connections for service_id=" + << service_id; return proto::connections::UNKNOWN_MEDIUM; } - - // TODO(ahlee): Add logging. + NEARBY_LOGS(INFO) + << "Ble succeed to start accepting connections for service_id=" + << service_id; } - // TODO(b/75047971): Add functionality to connect over Bluetooth. + if (ShouldAdvertiseBluetoothMacOverBle(power_level) || + ShouldAcceptBluetoothConnections(options)) { + if (bluetooth_medium_.IsAvailable() && + !bluetooth_medium_.IsAcceptingConnections(service_id)) { + if (!bluetooth_radio_.Enable() || + !bluetooth_medium_.StartAcceptingConnections( + service_id, {.accepted_cb = [this, client, local_endpoint_info]( + BluetoothSocket socket) { + if (!socket.IsValid()) { + NEARBY_LOG(INFO, + "Invalid socket in accept callback: name=%s", + std::string(local_endpoint_info).c_str()); + return; + } + RunOnPcpHandlerThread([this, client, local_endpoint_info, + socket = std::move(socket)]() mutable { + std::string remote_device_name = + socket.GetRemoteDevice().GetName(); + auto channel = absl::make_unique( + remote_device_name, socket); + ByteArray remote_device_info{remote_device_name}; - // Create a BLEAdvertisement. - // TODO(b/75047971): Add a bluetooth_adapter method to get the mac address. - string bluetooth_mac_address; - ScopedPtr> scoped_ble_advertisement_bytes( - BLEAdvertisement::toBytes(kBleAdvertisementVersion, getPCP(), - service_id_hash, local_endpoint_id, - local_endpoint_name, bluetooth_mac_address)); - if (scoped_ble_advertisement_bytes.isNull()) { - // TODO(ahlee): Add logging - medium_manager_->stopListeningForIncomingBleConnections(service_id); + OnIncomingConnection(client, remote_device_info, + std::move(channel), + proto::connections::Medium::BLUETOOTH); + }); + }})) { + NEARBY_LOGS(INFO) + << "BT failed to start accepting connections for service_id=" + << service_id; + ble_medium_.StopAcceptingConnections(service_id); + return proto::connections::UNKNOWN_MEDIUM; + } + NEARBY_LOGS(INFO) + << "BT succeed to start accepting connections for service_id=" + << service_id; + } + } + + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::StartBleAdvertising: service=%s: " + "make advertisement; id=%s, name=%s", + service_id.c_str(), local_endpoint_id.c_str(), + std::string(local_endpoint_info).c_str()); + // Generate a BleAdvertisement. If a fast advertisement service UUID was + // provided, create a fast BleAdvertisement. + ByteArray advertisement_bytes; + // TODO(b/169550050): Implement UWBAddress. + if (fast_advertisement) { + advertisement_bytes = ByteArray( + BleAdvertisement(kBleAdvertisementVersion, GetPcp(), local_endpoint_id, + local_endpoint_info, ByteArray{})); + } else { + const ByteArray service_id_hash = + GenerateHash(service_id, BleAdvertisement::kServiceIdHashLength); + std::string bluetooth_mac_address; + if (bluetooth_medium_.IsAvailable() && + ShouldAdvertiseBluetoothMacOverBle(power_level)) + bluetooth_mac_address = bluetooth_medium_.GetMacAddress(); + + advertisement_bytes = ByteArray( + BleAdvertisement(kBleAdvertisementVersion, GetPcp(), service_id_hash, + local_endpoint_id, local_endpoint_info, + bluetooth_mac_address, ByteArray{}, web_rtc_state)); + } + if (advertisement_bytes.Empty()) { + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::StartBleAdvertising: generate " + "BleAdvertisement failed"); + ble_medium_.StopAcceptingConnections(service_id); + return proto::connections::UNKNOWN_MEDIUM; + } else { + NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleAdvertising: generate " + "BleAdvertisement succeeded; advertisement_bytes=" + << advertisement_bytes.data(); + } + + NEARBY_LOG( + INFO, "P2pClusterPcpHandler::StartBleAdvertising: service_id=%s: come up", + service_id.c_str()); + + if (!ble_medium_.StartAdvertising(service_id, advertisement_bytes, + options.fast_advertisement_service_uuid)) { + NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleAdvertising: failed to " + "start advertising, advertisement_bytes=%p" + << advertisement_bytes.data(); + ble_medium_.StopAcceptingConnections(service_id); return proto::connections::UNKNOWN_MEDIUM; } - - // TODO(ahlee): Add logging - - if (!medium_manager_->startBleAdvertising( - service_id, scoped_ble_advertisement_bytes.release())) { - // TODO(ahlee): Add logging - medium_manager_->stopListeningForIncomingBleConnections(service_id); - return proto::connections::UNKNOWN_MEDIUM; - } - - // TODO(ahlee): Add logging + NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleAdvertising: service_id=" + << service_id << ": done"; return proto::connections::BLE; } -template -proto::connections::Medium P2PClusterPCPHandler::startBleDiscovery( - Ptr processor, - Ptr> client_proxy, const string& service_id) { - if (!medium_manager_->startBleScanning(service_id, processor)) { - // TODO(ahlee): logger.atDebug().log("In startBleDiscover(), client %d - // couldn't start scanning on BLE for service id %s.", - // client_proxy.getClientId(), service_id); +proto::connections::Medium P2pClusterPcpHandler::StartBleScanning( + BleDiscoveredPeripheralCallback callback, ClientProxy* client, + const std::string& service_id, + const std::string& fast_advertisement_service_uuid) { + if (bluetooth_radio_.Enable() && + ble_medium_.StartScanning(service_id, fast_advertisement_service_uuid, + std::move(callback))) { + NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleScanning: ok"; + return proto::connections::BLE; + } else { + NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleScanning: failed"; return proto::connections::UNKNOWN_MEDIUM; } - - // TODO(ahlee): logger.atVerbose().log("In startBleDiscovery(), client %d - // started scanning for BLE advertisements for serviceId %s.", - // client_proxy.getClietnId(), service_id); - - return proto::connections::BLE; } -template -proto::connections::Medium -P2PClusterPCPHandler::StartWifiLanAdvertising( - Ptr> client_proxy, absl::string_view service_id, - ConstPtr service_id_hash, absl::string_view local_endpoint_id, - absl::string_view local_endpoint_name) { +BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BleConnectImpl( + ClientProxy* client, BleEndpoint* endpoint) { + BlePeripheral& peripheral = endpoint->ble_peripheral; + + BleSocket ble_socket = ble_medium_.Connect(peripheral, endpoint->service_id); + if (!ble_socket.IsValid()) { + return BasePcpHandler::ConnectImplResult{ + .status = {Status::kBleError}, + }; + } + + auto channel = + absl::make_unique(endpoint->endpoint_id, ble_socket); + + return BasePcpHandler::ConnectImplResult{ + .medium = proto::connections::Medium::BLE, + .status = {Status::kSuccess}, + .endpoint_channel = std::move(channel), + }; +} + +proto::connections::Medium P2pClusterPcpHandler::StartWifiLanAdvertising( + ClientProxy* client, const std::string& service_id, + const ByteArray& service_id_hash, const std::string& local_endpoint_id, + const ByteArray& local_endpoint_info, WebRtcState web_rtc_state) { // Start listening for connections before advertising in case a connection // request comes in very quickly. - if (!medium_manager_->IsListeningForIncomingWifiLanConnections(service_id)) { - if (!medium_manager_->StartListeningForIncomingWifiLanConnections( - service_id, MakePtr(new IncomingWifiLanConnectionProcessor( - self_, client_proxy, local_endpoint_name)))) { - // TODO(b/149806065): logger.atWarning().log("In - // StartWifiLanAdvertising(%s), client %d failed to start listening for - // incoming WifiLan connections to ServiceId %s", local_endpoint_name, - // clientProxy.getClientId(), service_id); - return proto::connections::UNKNOWN_MEDIUM; - } - - // TODO(b/149806065): Add logging. + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::StartWifiLanAdvertising: service=%s: start", + service_id.c_str()); + if (wifi_lan_medium_.IsAcceptingConnections(service_id)) { + NEARBY_LOG(INFO, "WifiLan is already accepting connections for service=%s", + service_id.c_str()); + return proto::connections::UNKNOWN_MEDIUM; } - // Generate a WifiLanServiceInfo. - const string wifi_lan_service_info = - WifiLanServiceInfo::AsString(kWifiLanServiceInfoVersion, - getPCP(), - local_endpoint_id, - service_id_hash); - if (wifi_lan_service_info.empty()) { - // TODO(b/149806065): Add logging. + NEARBY_LOG( + INFO, + "P2pClusterPcpHandler::StartWifiLanAdvertising: service=%s: invoking", + service_id.c_str()); + if (!wifi_lan_medium_.StartAcceptingConnections( + service_id, {.accepted_cb = [this, client, local_endpoint_info]( + WifiLanSocket socket, + const std::string& service_id) { + if (!socket.IsValid()) { + NEARBY_LOG(INFO, "Invalid socket in accept callback: name=%s", + std::string(local_endpoint_info).c_str()); + return; + } + RunOnPcpHandlerThread([this, client, local_endpoint_info, + socket = std::move(socket)]() mutable { + std::string remote_service_info_name = + socket.GetRemoteWifiLanService().GetServiceName(); + auto channel = absl::make_unique( + remote_service_info_name, socket); + ByteArray remote_service_info{remote_service_info_name}; + + OnIncomingConnection(client, remote_service_info, + std::move(channel), + proto::connections::Medium::WIFI_LAN); + }); + }})) { + NEARBY_LOG(INFO, + "WifiLan failed to start accepting connections for service=%s", + service_id.c_str()); + return proto::connections::UNKNOWN_MEDIUM; + } + + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::StartWifiLanAdvertising: service=%s: " + "make name; id=%s, hash=%s, endpoint info=%s", + service_id.c_str(), local_endpoint_id.c_str(), + absl::BytesToHexString(service_id_hash.data()).c_str(), + absl::BytesToHexString(local_endpoint_info.data()).c_str()); + // Generate a WifiLanServiceInfo with which to become WifiLan discoverable. + // TODO(b/169550050): Implement UWBAddress. + WifiLanServiceInfo service_info{kWifiLanServiceInfoVersion, + GetPcp(), + local_endpoint_id, + service_id_hash, + local_endpoint_info, + ByteArray{}, + web_rtc_state}; + std::string service_info_name(service_info); + if (service_info_name.empty()) { + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::StartWifiLanAdvertising: generate " + "WifiLanServiceInfo failed"); + wifi_lan_medium_.StopAcceptingConnections(service_id); return proto::connections::UNKNOWN_MEDIUM; } else { - // TODO(b/149806065): Add logging. + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::StartWifiLanAdvertising: generate " + "WifiLanServiceInfo succeeded; service_info_name=%s", + service_info_name.c_str()); } + auto local_endpoint_info_name = service_info.GetEndpointInfoName(); - // TODO(b/149806065): Add logging + NEARBY_LOG( + INFO, + "P2pClusterPcpHandler::StartWifiLanAdvertising: service=%s: come up", + service_id.c_str()); - if (!medium_manager_->StartWifiLanAdvertising( - service_id, wifi_lan_service_info)) { - // TODO(b/149806065): Add logging - medium_manager_->StopWifiLanAdvertising(service_id); + if (!wifi_lan_medium_.StartAdvertising(service_id, service_info_name, + local_endpoint_info_name)) { + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::StartWifiLanAdvertising: failed to " + "start advertising, service_info_name=%s", + service_info_name.c_str()); + wifi_lan_medium_.StopAcceptingConnections(service_id); return proto::connections::UNKNOWN_MEDIUM; } + NEARBY_LOG(INFO, + "P2pClusterPcpHandler::StartWifiLanAdvertising: service=%s: done", + service_id.c_str()); return proto::connections::WIFI_LAN; } -template +proto::connections::Medium P2pClusterPcpHandler::StartWifiLanDiscovery( + WifiLanDiscoveredServiceCallback callback, ClientProxy* client, + const std::string& service_id) { + if (wifi_lan_medium_.StartDiscovery(service_id, std::move(callback))) { + NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartWifiLanDiscovery: ok"); + return proto::connections::WIFI_LAN; + } else { + NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartWifiLanDiscovery: failed"); + return proto::connections::UNKNOWN_MEDIUM; + } +} + +BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::WifiLanConnectImpl( + ClientProxy* client, WifiLanEndpoint* endpoint) { + WifiLanService& service = endpoint->wifi_lan_service; + + WifiLanSocket wifi_lan_socket = + wifi_lan_medium_.Connect(service, endpoint->service_id); + if (!wifi_lan_socket.IsValid()) { + return BasePcpHandler::ConnectImplResult{ + .status = {Status::kWifiLanError}, + }; + } + + auto channel = absl::make_unique( + endpoint->endpoint_id, wifi_lan_socket); + + return BasePcpHandler::ConnectImplResult{ + .medium = proto::connections::Medium::WIFI_LAN, + .status = {Status::kSuccess}, + .endpoint_channel = std::move(channel), + }; +} + proto::connections::Medium -P2PClusterPCPHandler::StartWifiLanDiscovery( - Ptr processor, - Ptr > client_proxy, absl::string_view service_id) { - if (!medium_manager_->StartWifiLanDiscovery(service_id, processor)) { - // TODO(b/149806065): Add logging. +P2pClusterPcpHandler::StartListeningForWebRtcConnections( + ClientProxy* client, const string& service_id, + const string& local_endpoint_id, const ByteArray& local_endpoint_info) { + if (!webrtc_medium_.IsAvailable()) { return proto::connections::UNKNOWN_MEDIUM; } - return proto::connections::WIFI_LAN; + if (!webrtc_medium_.IsAcceptingConnections()) { + mediums::PeerId self_id = CreatePeerIdFromAdvertisement( + service_id, local_endpoint_id, local_endpoint_info); + LocationHint location_hint; + location_hint.set_format(LocationStandard::UNKNOWN); + if (!webrtc_medium_.StartAcceptingConnections( + self_id, location_hint, + {[this, client, + local_endpoint_info](mediums::WebRtcSocketWrapper socket) { + if (!socket.IsValid()) { + NEARBY_LOG(INFO, "Invalid socket in accept callback: name=%s", + std::string(local_endpoint_info).c_str()); + return; + } + + RunOnPcpHandlerThread( + [this, client, socket = std::move(socket)]() { + string remote_device_name = "WebRtcSocket"; + auto channel = absl::make_unique( + remote_device_name, socket); + ByteArray remote_device_info{remote_device_name}; + + OnIncomingConnection(client, remote_device_info, + std::move(channel), + proto::connections::WEB_RTC); + }); + }})) { + return proto::connections::UNKNOWN_MEDIUM; + } + } + + return proto::connections::WEB_RTC; } -template -typename BasePCPHandler::ConnectImplResult -P2PClusterPCPHandler::bluetoothConnectImpl( - Ptr> client_proxy, - Ptr bluetooth_endpoint) { - Ptr remote_bluetooth_device = - bluetooth_endpoint->getBluetoothDevice(); +BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::WebRtcConnectImpl( + ClientProxy* client, WebRtcEndpoint* webrtc_endpoint) { + LocationHint location_hint; + location_hint.set_format(LocationStandard::UNKNOWN); +mediums::WebRtcSocketWrapper socket_wrapper = + webrtc_medium_.Connect(webrtc_endpoint->peer_id, location_hint); - Ptr bluetooth_socket = - medium_manager_->connectToBluetoothDevice( - remote_bluetooth_device, bluetooth_endpoint->getServiceId()); - if (bluetooth_socket.isNull()) { - return typename BasePCPHandler::ConnectImplResult( - proto::connections::Medium::BLUETOOTH, Status::BLUETOOTH_ERROR); +if (!socket_wrapper.IsValid()) { + return BasePcpHandler::ConnectImplResult{.status = {Status::kError}}; } - ScopedPtr> scoped_bluetooth_endpoint_channel( - this->endpoint_channel_manager_->createOutgoingBluetoothEndpointChannel( - bluetooth_endpoint->getEndpointId(), bluetooth_socket)); + auto channel = absl::make_unique( + webrtc_endpoint->endpoint_id, socket_wrapper); - if (scoped_bluetooth_endpoint_channel.isNull()) { - bluetooth_socket->close(); - bluetooth_socket.destroy(); // Avoid leaks. - return typename BasePCPHandler::ConnectImplResult( - proto::connections::Medium::BLUETOOTH, Status::ERROR); + if (!channel) { + socket_wrapper.Close(); + return BasePcpHandler::ConnectImplResult{.status = {Status::kError}}; } - // TODO(tracyzhou): Add logging. - return typename BasePCPHandler::ConnectImplResult( - scoped_bluetooth_endpoint_channel.release()); -} - -template -typename BasePCPHandler::ConnectImplResult -P2PClusterPCPHandler::bleConnectImpl( - Ptr> client_proxy, Ptr ble_endpoint) { - Ptr remote_ble_peripheral = ble_endpoint->getBlePeripheral(); - - Ptr ble_socket = medium_manager_->connectToBlePeripheral( - remote_ble_peripheral, ble_endpoint->getServiceId()); - - if (ble_socket.isNull()) { - return typename BasePCPHandler::ConnectImplResult( - proto::connections::Medium::BLE, Status::BLUETOOTH_ERROR); - } - - ScopedPtr> scoped_ble_endpoint_channel( - this->endpoint_channel_manager_->createOutgoingBLEEndpointChannel( - ble_endpoint->getEndpointId(), ble_socket)); - - if (scoped_ble_endpoint_channel.isNull()) { - ble_socket->close(); - ble_socket.destroy(); // Avoid leaks. - return typename BasePCPHandler::ConnectImplResult( - proto::connections::Medium::BLE, Status::ERROR); - } - - // TODO(tracyzhou): Add logging. - return typename BasePCPHandler::ConnectImplResult( - scoped_ble_endpoint_channel.release()); -} - -template -string P2PClusterPCPHandler::getBlePeripheralId( - Ptr ble_peripheral) { -#if BLE_V2_IMPLEMENTED - return string(ble_peripheral->getId()->getData(), - ble_peripheral->getId()->size()); -#else - return ble_peripheral->getBluetoothDevice()->getName(); -#endif -} - -template -typename BasePCPHandler::ConnectImplResult -P2PClusterPCPHandler::WifiLanConnectImpl( - Ptr> client_proxy, - Ptr wifi_lan_endpoint) { - Ptr remote_wifi_lan_service = - wifi_lan_endpoint->GetWifiLanService(); - - Ptr wifi_lan_socket = medium_manager_->ConnectToWifiLanService( - remote_wifi_lan_service, wifi_lan_endpoint->getServiceId()); - - if (wifi_lan_socket.isNull()) { - return typename BasePCPHandler::ConnectImplResult( - proto::connections::Medium::WIFI_LAN, Status::BLUETOOTH_ERROR); - } - - ScopedPtr> scoped_wifi_lan_endpoint_channel( - this->endpoint_channel_manager_->CreateOutgoingWifiLanEndpointChannel( - wifi_lan_endpoint->getEndpointId(), wifi_lan_socket)); - - if (scoped_wifi_lan_endpoint_channel.isNull()) { - wifi_lan_socket->Close(); - wifi_lan_socket.destroy(); // Avoid leaks. - return typename BasePCPHandler::ConnectImplResult( - proto::connections::Medium::WIFI_LAN, Status::ERROR); - } - - // TODO(b/149806065): Add logging. - return typename BasePCPHandler::ConnectImplResult( - scoped_wifi_lan_endpoint_channel.release()); + return BasePcpHandler::ConnectImplResult{ + .medium = proto::connections::Medium::WEB_RTC, + .status = {Status::kSuccess}, + .endpoint_channel = std::move(channel)}; } } // namespace connections diff --git a/cpp/core/internal/p2p_cluster_pcp_handler.h b/cpp/core/internal/p2p_cluster_pcp_handler.h index 26d60b6e..4922d6d0 100644 --- a/cpp/core/internal/p2p_cluster_pcp_handler.h +++ b/cpp/core/internal/p2p_cluster_pcp_handler.h @@ -1,25 +1,27 @@ #ifndef CORE_INTERNAL_P2P_CLUSTER_PCP_HANDLER_H_ #define CORE_INTERNAL_P2P_CLUSTER_PCP_HANDLER_H_ +#include #include -#include "core/internal/bandwidth_upgrade_manager.h" #include "core/internal/base_pcp_handler.h" #include "core/internal/ble_advertisement.h" -#include "core/internal/ble_compat.h" #include "core/internal/bluetooth_device_name.h" +#include "core/internal/bwu_manager.h" #include "core/internal/client_proxy.h" #include "core/internal/endpoint_channel_manager.h" #include "core/internal/endpoint_manager.h" -#include "core/internal/medium_manager.h" +#include "core/internal/mediums/bluetooth_classic.h" +#include "core/internal/mediums/mediums.h" +#include "core/internal/mediums/webrtc.h" +#include "core/internal/mediums/webrtc/peer_id.h" #include "core/internal/pcp.h" #include "core/internal/wifi_lan_service_info.h" #include "core/options.h" #include "core/strategy.h" -#include "platform/api/bluetooth_classic.h" -#include "platform/byte_array.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "platform/base/byte_array.h" +#include "platform/public/bluetooth_classic.h" +#include "platform/public/wifi_lan.h" #include "proto/connections_enums.pb.h" namespace location { @@ -31,490 +33,181 @@ namespace connections { // and all devices are considered equal. For asymmetric mediums, where one // device is a server and the others are clients, use P2PStarPCPHandler instead. // -//

Currently, this implementation advertises/discovers over BLE and Bluetooth -// and connects over Bluetooth. -template -class P2PClusterPCPHandler : public BasePCPHandler { +// Currently, this implementation advertises/discovers over Bluetooth and +// connects over Bluetooth. +class P2pClusterPcpHandler : public BasePcpHandler { public: - P2PClusterPCPHandler(Ptr> medium_manager, - Ptr> endpoint_manager, - Ptr endpoint_channel_manager, - Ptr bandwidth_upgrade_manager); - ~P2PClusterPCPHandler() override; - - Strategy getStrategy() override; - PCP::Value getPCP() override; + P2pClusterPcpHandler(Mediums* mediums, EndpointManager* endpoint_manager, + EndpointChannelManager* channel_manager, + BwuManager* bwu_manager, + Pcp pcp = Pcp::kP2pCluster); + ~P2pClusterPcpHandler() override = default; protected: - std::vector getConnectionMediumsByPriority() + std::vector GetConnectionMediumsByPriority() override; - proto::connections::Medium getDefaultUpgradeMedium() override; + proto::connections::Medium GetDefaultUpgradeMedium() override; // @PCPHandlerThread - Ptr::StartOperationResult> - startAdvertisingImpl(Ptr> client_proxy, - const string& service_id, - const string& local_endpoint_id, - const string& local_endpoint_name, - const AdvertisingOptions& options) override; + BasePcpHandler::StartOperationResult StartAdvertisingImpl( + ClientProxy* client, const std::string& service_id, + const std::string& local_endpoint_id, + const ByteArray& local_endpoint_info, + const ConnectionOptions& options) override; // @PCPHandlerThread - Status::Value stopAdvertisingImpl( - Ptr> client_proxy) override; + Status StopAdvertisingImpl(ClientProxy* client) override; // @PCPHandlerThread - Ptr::StartOperationResult> - startDiscoveryImpl(Ptr> client_proxy, - const string& service_id, - const DiscoveryOptions& options) override; + BasePcpHandler::StartOperationResult StartDiscoveryImpl( + ClientProxy* client, const std::string& service_id, + const ConnectionOptions& options) override; // @PCPHandlerThread - Status::Value stopDiscoveryImpl( - Ptr> client_proxy) override; + Status StopDiscoveryImpl(ClientProxy* client) override; // @PCPHandlerThread - typename BasePCPHandler::ConnectImplResult connectImpl( - Ptr> client_proxy, - Ptr::DiscoveredEndpoint> endpoint) - override; + Status InjectEndpointImpl( + ClientProxy* client, const std::string& service_id, + const OutOfBandConnectionMetadata& metadata) override; + + // @PCPHandlerThread + BasePcpHandler::ConnectImplResult ConnectImpl( + ClientProxy* client, + BasePcpHandler::DiscoveredEndpoint* endpoint) override; private: - template - friend class IncomingBluetoothConnectionProcessor; - template - friend class IncomingBleConnectionProcessor; - template - friend class IncomingWifiLanConnectionProcessor; - template - friend class FoundBluetoothAdvertisementProcessor; - template - friend class FoundBleAdvertisementProcessor; - template - friend class FoundWifiLanServiceProcessor; + struct BluetoothEndpoint : public BasePcpHandler::DiscoveredEndpoint { + BluetoothEndpoint(DiscoveredEndpoint endpoint, BluetoothDevice device) + : DiscoveredEndpoint(std::move(endpoint)), + bluetooth_device(std::move(device)) {} - class IncomingBluetoothConnectionProcessor - : public MediumManager::IncomingBluetoothConnectionProcessor { - public: - IncomingBluetoothConnectionProcessor( - Ptr> pcp_handler, - Ptr> client_proxy, - const string& local_endpoint_name); - - void onIncomingBluetoothConnection( - Ptr bluetooth_socket) override; - - private: - class OnIncomingBluetoothConnectionRunnable : public Runnable { - public: - OnIncomingBluetoothConnectionRunnable( - Ptr> pcp_handler, - Ptr> client_proxy, - Ptr bluetooth_socket); - - void run() override; - - private: - Ptr> pcp_handler_; - Ptr> client_proxy_; - Ptr bluetooth_socket_; - }; - - Ptr> pcp_handler_; - Ptr> client_proxy_; - const string local_endpoint_name_; + BluetoothDevice bluetooth_device; + }; + struct BleEndpoint : public BasePcpHandler::DiscoveredEndpoint { + BleEndpoint(DiscoveredEndpoint endpoint, BlePeripheral peripheral) + : DiscoveredEndpoint(std::move(endpoint)), + ble_peripheral(std::move(peripheral)) {} + BlePeripheral ble_peripheral; }; - class IncomingBleConnectionProcessor - : public MediumManager::IncomingBleConnectionProcessor { + // Holds the state required to re-create a BleEndpoint we see on a + // BlePeripheral, so BlePeripheralLostHandler can call + // BasePcpHandler::OnEndpointLost() with the same information as was passed + // in to BasePCPHandler::onEndpointFound(). + struct BleEndpointState { public: - IncomingBleConnectionProcessor( - Ptr> pcp_handler, - Ptr> client_proxy, - const string& local_endpoint_name); + BleEndpointState(const string& endpoint_id, const ByteArray& endpoint_info) + : endpoint_id(endpoint_id), endpoint_info(endpoint_info) {} - void onIncomingBleConnection(Ptr ble_socket, - const string& service_id) override; + std::string endpoint_id; + ByteArray endpoint_info; + }; + struct WifiLanEndpoint : public BasePcpHandler::DiscoveredEndpoint { + WifiLanEndpoint(DiscoveredEndpoint endpoint, WifiLanService service) + : DiscoveredEndpoint(std::move(endpoint)), + wifi_lan_service(std::move(service)) {} - private: - class OnIncomingBleConnectionRunnable : public Runnable { - public: - OnIncomingBleConnectionRunnable( - Ptr> pcp_handler, - Ptr> client_proxy, Ptr ble_socket); - - void run() override; - - private: - Ptr> pcp_handler_; - Ptr> client_proxy_; - Ptr ble_socket_; - }; - - Ptr> pcp_handler_; - Ptr> client_proxy_; - const string local_endpoint_name_; + WifiLanService wifi_lan_service; }; - class IncomingWifiLanConnectionProcessor - : public MediumManager::IncomingWifiLanConnectionProcessor { - public: - IncomingWifiLanConnectionProcessor( - Ptr> pcp_handler, - Ptr> client_proxy, - absl::string_view local_endpoint_name); + using BluetoothDiscoveredDeviceCallback = + BluetoothClassic::DiscoveredDeviceCallback; + using BleDiscoveredPeripheralCallback = Ble::DiscoveredPeripheralCallback; + using WifiLanDiscoveredServiceCallback = WifiLan::DiscoveredServiceCallback; - void OnIncomingWifiLanConnection( - Ptr wifi_lan_socket) override; + static constexpr BluetoothDeviceName::Version kBluetoothDeviceNameVersion = + BluetoothDeviceName::Version::kV1; + static constexpr BleAdvertisement::Version kBleAdvertisementVersion = + BleAdvertisement::Version::kV1; + static constexpr WifiLanServiceInfo::Version kWifiLanServiceInfoVersion = + WifiLanServiceInfo::Version::kV1; - private: - class OnIncomingWifiLanConnectionRunnable : public Runnable { - public: - OnIncomingWifiLanConnectionRunnable( - Ptr> pcp_handler, - Ptr> client_proxy, - Ptr wifi_lan_socket); + static ByteArray GenerateHash(const std::string& source, size_t size); + static bool ShouldAdvertiseBluetoothMacOverBle(PowerLevel power_level); + static bool ShouldAcceptBluetoothConnections( + const ConnectionOptions& options); - void run() override; + // Bluetooth + bool IsRecognizedBluetoothEndpoint(const std::string& name_string, + const std::string& service_id, + const BluetoothDeviceName& name) const; + void BluetoothDeviceDiscoveredHandler(ClientProxy* client, + const std::string& service_id, + BluetoothDevice& device); + void BluetoothDeviceLostHandler(ClientProxy* client, + const std::string& service_id, + BluetoothDevice& device); + proto::connections::Medium StartBluetoothAdvertising( + ClientProxy* client, const std::string& service_id, + const ByteArray& service_id_hash, const std::string& local_endpoint_id, + const ByteArray& local_endpoint_info, WebRtcState web_rtc_state); + proto::connections::Medium StartBluetoothDiscovery( + BluetoothDiscoveredDeviceCallback callback, ClientProxy* client, + const std::string& service_id); + BasePcpHandler::ConnectImplResult BluetoothConnectImpl( + ClientProxy* client, BluetoothEndpoint* endpoint); - private: - Ptr> pcp_handler_; - Ptr> client_proxy_; - Ptr wifi_lan_socket_; - }; - - Ptr> pcp_handler_; - Ptr> client_proxy_; - const string local_endpoint_name_; - }; - - class FoundBluetoothAdvertisementProcessor - : public MediumManager::FoundBluetoothDeviceProcessor { - public: - FoundBluetoothAdvertisementProcessor( - Ptr> pcp_handler, - Ptr> client_proxy, const string& service_id); - - void onFoundBluetoothDevice(Ptr bluetooth_device) override; - void onLostBluetoothDevice(Ptr bluetooth_device) override; - - private: - class OnFoundBluetoothDeviceRunnable : public Runnable { - public: - OnFoundBluetoothDeviceRunnable( - Ptr> pcp_handler, - Ptr> client_proxy, - Ptr - found_bluetooth_advertisement_processor, - const string& service_id, Ptr bluetooth_device); - - void run() override; - - private: - Ptr> pcp_handler_; - Ptr> client_proxy_; - Ptr - found_bluetooth_advertisement_processor_; - const string service_id_; - ScopedPtr> bluetooth_device_; - }; - - class OnLostBluetoothDeviceRunnable : public Runnable { - public: - OnLostBluetoothDeviceRunnable( - Ptr> pcp_handler, - Ptr> client_proxy, - Ptr - found_bluetooth_advertisement_processor, - const string& service_id, Ptr bluetooth_device); - - void run() override; - - private: - Ptr> pcp_handler_; - Ptr> client_proxy_; - Ptr - found_bluetooth_advertisement_processor_; - const string service_id_; - ScopedPtr> bluetooth_device_; - }; - - bool isRecognizedBluetoothEndpoint( - const string& found_bluetooth_device_name, - Ptr bluetooth_device_name); - - Ptr> pcp_handler_; - Ptr> client_proxy_; - const string service_id_; - ScopedPtr> expected_service_id_hash_; - std::shared_ptr self_{this, - [](void*) {}}; - }; - - class FoundBleAdvertisementProcessor - : public MediumManager::FoundBlePeripheralProcessor { - public: - FoundBleAdvertisementProcessor( - Ptr> pcp_handler, - Ptr> client_proxy); - - void onFoundBlePeripheral(Ptr ble_peripheral, - const string& service_id, - ConstPtr advertisement_bytes) override; - void onLostBlePeripheral(Ptr ble_peripheral, - const string& service_id) override; - - private: - class OnFoundBlePeripheralRunnable : public Runnable { - public: - OnFoundBlePeripheralRunnable( - Ptr> pcp_handler, - Ptr> client_proxy, - Ptr found_ble_advertisement_processor, - const string& service_id, Ptr ble_peripheral, - ConstPtr advertisement_bytes); - - void run() override; - - private: - Ptr> pcp_handler_; - Ptr> client_proxy_; - Ptr found_ble_advertisement_processor_; - const string service_id_; - ScopedPtr> ble_peripheral_; - ScopedPtr> advertisement_bytes_; - ScopedPtr> expected_service_id_hash_; - }; - - class OnLostBlePeripheralRunnable : public Runnable { - public: - OnLostBlePeripheralRunnable( - Ptr> pcp_handler, - Ptr> client_proxy, - Ptr found_ble_advertisement_processor, - const string& service_id, Ptr ble_peripheral); - - void run() override; - - private: - Ptr> pcp_handler_; - Ptr> client_proxy_; - Ptr found_ble_advertisement_processor_; - const string service_id_; - ScopedPtr> ble_peripheral_; - }; - - // Holds the state required to re-create a BLEEndpoint we see on a - // BLEPeripheral, so OnLostBlePeripheralRunnable::run() can call - // BasePCPHandler::onEndpointLost() with the same information as was passed - // in to BasePCPHandler::onEndpointFound(). - struct BLEEndpointState { - public: - BLEEndpointState(const string& endpoint_id, const string& endpoint_name) - : endpoint_id(endpoint_id), endpoint_name(endpoint_name) {} - - const string endpoint_id; - const string endpoint_name; - }; - - Ptr> pcp_handler_; - Ptr> client_proxy_; - - // Maps a BLEPeripheral to its corresponding BLEEndpointState. - typedef std::map FoundBLEEndpointsMap; - FoundBLEEndpointsMap found_ble_endpoints_; - std::shared_ptr self_{this, [](void*) {}}; - }; - - class FoundWifiLanServiceProcessor - : public MediumManager::FoundWifiLanServiceProcessor { - public: - FoundWifiLanServiceProcessor( - Ptr> pcp_handler, - Ptr> client_proxy, - absl::string_view service_id); - - void OnFoundWifiLanService(Ptr wifi_lan_service) override; - void OnLostWifiLanService(Ptr wifi_lan_service) override; - - private: - class OnFoundWifiLanServiceRunnable : public Runnable { - public: - OnFoundWifiLanServiceRunnable( - Ptr> pcp_handler, - Ptr> client_proxy, - Ptr found_wifi_lan_service_processor, - absl::string_view service_id, Ptr wifi_lan_service); - - void run() override; - - private: - Ptr> pcp_handler_; - Ptr> client_proxy_; - Ptr found_wifi_lan_service_processor_; - const string service_id_; - ScopedPtr> wifi_lan_service_; - ScopedPtr> expected_service_id_hash_; - }; - - class OnLostWifiLanServiceRunnable : public Runnable { - public: - OnLostWifiLanServiceRunnable( - Ptr> pcp_handler, - Ptr> client_proxy, - Ptr found_wifi_lan_service_processor, - absl::string_view service_id, Ptr wifi_lan_service); - - void run() override; - - private: - Ptr> pcp_handler_; - Ptr> client_proxy_; - Ptr found_wifi_lan_service_processor_; - const string service_id_; - ScopedPtr> wifi_lan_service_; - }; - - bool IsRecognizedWifiLanEndpoint( - Ptr wifi_lan_service_info); - - Ptr> pcp_handler_; - Ptr> client_proxy_; - const string service_id_; - ScopedPtr> expected_service_id_hash_; - std::shared_ptr self_{this, [](void*) {}}; - }; - - class BluetoothEndpoint - : public BasePCPHandler::DiscoveredEndpoint { - public: - Ptr getBluetoothDevice() { - return bluetooth_device_.get(); - } - string getEndpointId() override { return endpoint_id_; } - string getEndpointName() override { return endpoint_name_; } - string getServiceId() override { return service_id_; } - proto::connections::Medium getMedium() override { - return proto::connections::Medium::BLUETOOTH; - } - - private: - BluetoothEndpoint(Ptr bluetooth_device, - const string& endpoint_id, const string& endpoint_name, - const string& service_id) - : bluetooth_device_(bluetooth_device), - endpoint_id_(endpoint_id), - endpoint_name_(endpoint_name), - service_id_(service_id) {} - - friend class FoundBluetoothAdvertisementProcessor; - - ScopedPtr> bluetooth_device_; - const string endpoint_id_; - const string endpoint_name_; - const string service_id_; - }; - - class BLEEndpoint : public BasePCPHandler::DiscoveredEndpoint { - public: - Ptr getBlePeripheral() { return ble_peripheral_.get(); } - string getEndpointId() override { return endpoint_id_; } - string getEndpointName() override { return endpoint_name_; } - string getServiceId() override { return service_id_; } - proto::connections::Medium getMedium() override { - return proto::connections::Medium::BLE; - } - - private: - BLEEndpoint(Ptr ble_peripheral, const string& endpoint_id, - const string& endpoint_name, const string& service_id) - : ble_peripheral_(ble_peripheral), - endpoint_id_(endpoint_id), - endpoint_name_(endpoint_name), - service_id_(service_id) {} - - friend class FoundBleAdvertisementProcessor; - - ScopedPtr> ble_peripheral_; - const string endpoint_id_; - const string endpoint_name_; - const string service_id_; - }; - - class WifiLanEndpoint : public BasePCPHandler::DiscoveredEndpoint { - public: - Ptr GetWifiLanService() { return wifi_lan_service_.get(); } - string getEndpointId() override { return endpoint_id_; } - string getEndpointName() override { return endpoint_name_; } - string getServiceId() override { return service_id_; } - proto::connections::Medium getMedium() override { - return proto::connections::Medium::WIFI_LAN; - } - - private: - WifiLanEndpoint(Ptr wifi_lan_service, - absl::string_view endpoint_id, - absl::string_view endpoint_name, - absl::string_view service_id) - : wifi_lan_service_(wifi_lan_service), - endpoint_id_(endpoint_id), - endpoint_name_(endpoint_name), - service_id_(service_id) {} - - friend class FoundWifiLanServiceProcessor; - - ScopedPtr> wifi_lan_service_; - const string endpoint_id_; - const string endpoint_name_; - const string service_id_; - }; - - static const BluetoothDeviceName::Version::Value kBluetoothDeviceNameVersion; - static const BLEAdvertisement::Version::Value kBleAdvertisementVersion; - static const WifiLanServiceInfo::Version kWifiLanServiceInfoVersion; - - static ConstPtr generateHash(const string& source, size_t size); - static string getBlePeripheralId(Ptr ble_peripheral); - - proto::connections::Medium startBluetoothAdvertising( - Ptr> client_proxy, const string& service_id, - ConstPtr service_id_hash, const string& local_endpoint_id, - const string& local_endpoint_name); - proto::connections::Medium startBluetoothDiscovery( - Ptr processor, - Ptr> client_proxy, const string& service_id); - typename BasePCPHandler::ConnectImplResult bluetoothConnectImpl( - Ptr> client_proxy, - Ptr bluetooth_endpoint); - - proto::connections::Medium startBleAdvertising( - Ptr> client_proxy, const string& service_id, - ConstPtr service_id_hash, const string& local_endpoint_id, - const string& local_endpoint_name); - proto::connections::Medium startBleDiscovery( - Ptr processor, - Ptr> client_proxy, const string& service_id); - typename BasePCPHandler::ConnectImplResult bleConnectImpl( - Ptr> client_proxy, Ptr ble_endpoint); + // Ble + // Maps a BlePeripheral to its corresponding BleEndpointState. + absl::flat_hash_map found_ble_endpoints_; + bool IsRecognizedBleEndpoint(const std::string& service_id, + const BleAdvertisement& advertisement) const; + void BlePeripheralDiscoveredHandler(ClientProxy* client, + BlePeripheral& peripheral, + const std::string& service_id, + const ByteArray& advertisement_bytes, + bool fast_advertisement); + void BlePeripheralLostHandler(ClientProxy* client, BlePeripheral& peripheral, + const std::string& service_id); + proto::connections::Medium StartBleAdvertising( + ClientProxy* client, const std::string& service_id, + const std::string& local_endpoint_id, + const ByteArray& local_endpoint_info, const ConnectionOptions& options, + WebRtcState web_rtc_state); + proto::connections::Medium StartBleScanning( + BleDiscoveredPeripheralCallback callback, ClientProxy* client, + const std::string& service_id, + const std::string& fast_advertisement_service_uuid); + BasePcpHandler::ConnectImplResult BleConnectImpl(ClientProxy* client, + BleEndpoint* endpoint); + // WifiLan + bool IsRecognizedWifiLanEndpoint( + const std::string& service_id, + const WifiLanServiceInfo& service_info) const; + void WifiLanServiceDiscoveredHandler(ClientProxy* client, + WifiLanService& service, + const std::string& service_id); + void WifiLanServiceLostHandler(ClientProxy* client, WifiLanService& service, + const std::string& service_id); proto::connections::Medium StartWifiLanAdvertising( - Ptr> client_proxy, absl::string_view service_id, - ConstPtr service_id_hash, absl::string_view local_endpoint_id, - absl::string_view local_endpoint_name); + ClientProxy* client, const std::string& service_id, + const ByteArray& service_id_hash, const std::string& local_endpoint_id, + const ByteArray& local_endpoint_info, WebRtcState web_rtc_state); proto::connections::Medium StartWifiLanDiscovery( - Ptr processor, - Ptr> client_proxy, absl::string_view service_id); - typename BasePCPHandler::ConnectImplResult WifiLanConnectImpl( - Ptr> client_proxy, - Ptr wifi_lan_endpoint); + WifiLanDiscoveredServiceCallback callback, ClientProxy* client, + const std::string& service_id); + BasePcpHandler::ConnectImplResult WifiLanConnectImpl( + ClientProxy* client, WifiLanEndpoint* endpoint); - Ptr> medium_manager_; - std::shared_ptr self_{this, [](void*) {}}; + // WebRtc + proto::connections::Medium StartListeningForWebRtcConnections( + ClientProxy* client, const std::string& service_id, + const std::string& local_endpoint_id, + const ByteArray& local_endpoint_info); + BasePcpHandler::ConnectImplResult WebRtcConnectImpl( + ClientProxy* client, WebRtcEndpoint* webrtc_endpoint); + + BluetoothRadio& bluetooth_radio_; + BluetoothClassic& bluetooth_medium_; + Ble& ble_medium_; + WifiLan& wifi_lan_medium_; + mediums::WebRtc& webrtc_medium_; }; } // namespace connections } // namespace nearby } // namespace location -#include "core/internal/p2p_cluster_pcp_handler.cc" - #endif // CORE_INTERNAL_P2P_CLUSTER_PCP_HANDLER_H_ diff --git a/cpp/core_v2/internal/p2p_cluster_pcp_handler_test.cc b/cpp/core/internal/p2p_cluster_pcp_handler_test.cc similarity index 93% rename from cpp/core_v2/internal/p2p_cluster_pcp_handler_test.cc rename to cpp/core/internal/p2p_cluster_pcp_handler_test.cc index 8ac6064b..7efe4e6f 100644 --- a/cpp/core_v2/internal/p2p_cluster_pcp_handler_test.cc +++ b/cpp/core/internal/p2p_cluster_pcp_handler_test.cc @@ -1,12 +1,12 @@ -#include "core_v2/internal/p2p_cluster_pcp_handler.h" +#include "core/internal/p2p_cluster_pcp_handler.h" #include -#include "core_v2/internal/bwu_manager.h" -#include "core_v2/options.h" -#include "platform_v2/base/medium_environment.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/logging.h" +#include "core/internal/bwu_manager.h" +#include "core/options.h" +#include "platform/base/medium_environment.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/logging.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/time/time.h" @@ -186,8 +186,11 @@ TEST_P(P2pClusterPcpHandlerTest, CanConnect) { const std::string& endpoint_id, const ByteArray& endpoint_info, const std::string& service_id) { - NEARBY_LOG(INFO, "Device discovered: id=%s", - endpoint_id.c_str()); + NEARBY_LOG( + INFO, + "Device discovered: id=%s, endpoint_info=%s", + endpoint_id.c_str(), + std::string{endpoint_info}.c_str()); discovered = { .endpoint_id = endpoint_id, .endpoint_info = endpoint_info, diff --git a/cpp/core/internal/p2p_point_to_point_pcp_handler.cc b/cpp/core/internal/p2p_point_to_point_pcp_handler.cc index 7623f490..18013b4c 100644 --- a/cpp/core/internal/p2p_point_to_point_pcp_handler.cc +++ b/cpp/core/internal/p2p_point_to_point_pcp_handler.cc @@ -4,56 +4,44 @@ namespace location { namespace nearby { namespace connections { -template -P2PPointToPointPCPHandler::P2PPointToPointPCPHandler( - Ptr > medium_manager, - Ptr > endpoint_manager, - Ptr endpoint_channel_manager, - Ptr bandwidth_upgrade_manager) - : P2PStarPCPHandler(medium_manager, endpoint_manager, - endpoint_channel_manager, - bandwidth_upgrade_manager), - medium_manager_(medium_manager) {} +P2pPointToPointPcpHandler::P2pPointToPointPcpHandler( + Mediums& mediums, EndpointManager& endpoint_manager, + EndpointChannelManager& channel_manager, BwuManager& bwu_manager, Pcp pcp) + : P2pStarPcpHandler(mediums, endpoint_manager, channel_manager, bwu_manager, + pcp) {} -template -Strategy P2PPointToPointPCPHandler::getStrategy() { - return Strategy::kP2PPointToPoint; -} - -template -PCP::Value P2PPointToPointPCPHandler::getPCP() { - return PCP::P2P_POINT_TO_POINT; -} - -template std::vector -P2PPointToPointPCPHandler::getConnectionMediumsByPriority() { +P2pPointToPointPcpHandler::GetConnectionMediumsByPriority() { std::vector mediums; - if (medium_manager_->isBluetoothAvailable()) { + if (mediums_->GetWifiLan().IsAvailable()) { + mediums.push_back(proto::connections::WIFI_LAN); + } + if (mediums_->GetWebRtc().IsAvailable()) { + mediums.push_back(proto::connections::WEB_RTC); + } + if (mediums_->GetBluetoothClassic().IsAvailable()) { mediums.push_back(proto::connections::BLUETOOTH); } - if (medium_manager_->isBleAvailable()) { + if (mediums_->GetBle().IsAvailable()) { mediums.push_back(proto::connections::BLE); } return mediums; } -template -bool P2PPointToPointPCPHandler::canSendOutgoingConnection( - Ptr > client_proxy) { +bool P2pPointToPointPcpHandler::CanSendOutgoingConnection( + ClientProxy* client) const { // For point to point, we can only send an outgoing connection while we have // no other connections. - return !this->hasOutgoingConnections(client_proxy) && - !this->hasIncomingConnections(client_proxy); + return !this->HasOutgoingConnections(client) && + !this->HasIncomingConnections(client); } -template -bool P2PPointToPointPCPHandler::canReceiveIncomingConnection( - Ptr > client_proxy) { +bool P2pPointToPointPcpHandler::CanReceiveIncomingConnection( + ClientProxy* client) const { // For point to point, we can only receive an incoming connection while we // have no other connections. - return !this->hasOutgoingConnections(client_proxy) && - !this->hasIncomingConnections(client_proxy); + return !this->HasOutgoingConnections(client) && + !this->HasIncomingConnections(client); } } // namespace connections diff --git a/cpp/core/internal/p2p_point_to_point_pcp_handler.h b/cpp/core/internal/p2p_point_to_point_pcp_handler.h index 0b75dbef..abf89a70 100644 --- a/cpp/core/internal/p2p_point_to_point_pcp_handler.h +++ b/cpp/core/internal/p2p_point_to_point_pcp_handler.h @@ -1,14 +1,11 @@ #ifndef CORE_INTERNAL_P2P_POINT_TO_POINT_PCP_HANDLER_H_ #define CORE_INTERNAL_P2P_POINT_TO_POINT_PCP_HANDLER_H_ -#include "core/internal/bandwidth_upgrade_manager.h" #include "core/internal/endpoint_channel_manager.h" #include "core/internal/endpoint_manager.h" -#include "core/internal/medium_manager.h" #include "core/internal/p2p_star_pcp_handler.h" #include "core/internal/pcp.h" #include "core/strategy.h" -#include "platform/ptr.h" namespace location { namespace nearby { @@ -17,39 +14,27 @@ namespace connections { // Concrete implementation of the PCPHandler for the P2P_POINT_TO_POINT. This // PCP is for mediums that have limitations on the number of simultaneous // connections; all mediums in P2P_STAR are valid for P2P_POINT_TO_POINT, but -// not all mediums in P2P_POINT_TO_POINT and valid for P2P_STAR. +// not all mediums in P2P_POINT_TO_POINT are valid for P2P_STAR. // -//

Currently, this implementation advertises/discovers over BLE and Bluetooth -// and connects over Bluetooth, eventually upgrading to Wifi Hotspot. -template -class P2PPointToPointPCPHandler : public P2PStarPCPHandler { +// Currently, this implementation advertises/discovers over Bluetooth +// and connects over Bluetooth. +class P2pPointToPointPcpHandler : public P2pStarPcpHandler { public: - P2PPointToPointPCPHandler( - Ptr > medium_manager, - Ptr > endpoint_manager, - Ptr endpoint_channel_manager, - Ptr bandwidth_upgrade_manager); - - Strategy getStrategy() override; - PCP::Value getPCP() override; + P2pPointToPointPcpHandler(Mediums& mediums, EndpointManager& endpoint_manager, + EndpointChannelManager& channel_manager, + BwuManager& bwu_manager, + Pcp pcp = Pcp::kP2pPointToPoint); protected: - std::vector getConnectionMediumsByPriority() + std::vector GetConnectionMediumsByPriority() override; - bool canSendOutgoingConnection( - Ptr > client_proxy) override; - bool canReceiveIncomingConnection( - Ptr > client_proxy) override; - - private: - Ptr > medium_manager_; + bool CanSendOutgoingConnection(ClientProxy* client) const override; + bool CanReceiveIncomingConnection(ClientProxy* client) const override; }; } // namespace connections } // namespace nearby } // namespace location -#include "core/internal/p2p_point_to_point_pcp_handler.cc" - #endif // CORE_INTERNAL_P2P_POINT_TO_POINT_PCP_HANDLER_H_ diff --git a/cpp/core/internal/p2p_star_pcp_handler.cc b/cpp/core/internal/p2p_star_pcp_handler.cc index 320bc1a0..11941b4e 100644 --- a/cpp/core/internal/p2p_star_pcp_handler.cc +++ b/cpp/core/internal/p2p_star_pcp_handler.cc @@ -6,64 +6,47 @@ namespace location { namespace nearby { namespace connections { -template -P2PStarPCPHandler::P2PStarPCPHandler( - Ptr > medium_manager, - Ptr > endpoint_manager, - Ptr endpoint_channel_manager, - Ptr bandwidth_upgrade_manager) - : P2PClusterPCPHandler(medium_manager, endpoint_manager, - endpoint_channel_manager, - bandwidth_upgrade_manager), - medium_manager_(medium_manager) {} +P2pStarPcpHandler::P2pStarPcpHandler(Mediums& mediums, + EndpointManager& endpoint_manager, + EndpointChannelManager& channel_manager, + BwuManager& bwu_manager, Pcp pcp) + : P2pClusterPcpHandler(&mediums, &endpoint_manager, &channel_manager, + &bwu_manager, pcp) {} -template -P2PStarPCPHandler::~P2PStarPCPHandler() {} - -template -Strategy P2PStarPCPHandler::getStrategy() { - return Strategy::kP2PStar; -} - -template -PCP::Value P2PStarPCPHandler::getPCP() { - return PCP::P2P_STAR; -} - -template std::vector -P2PStarPCPHandler::getConnectionMediumsByPriority() { +P2pStarPcpHandler::GetConnectionMediumsByPriority() { std::vector mediums; - if (medium_manager_->isBluetoothAvailable()) { + if (mediums_->GetWifiLan().IsAvailable()) { + mediums.push_back(proto::connections::WIFI_LAN); + } + if (mediums_->GetWebRtc().IsAvailable()) { + mediums.push_back(proto::connections::WEB_RTC); + } + if (mediums_->GetBluetoothClassic().IsAvailable()) { mediums.push_back(proto::connections::BLUETOOTH); } - if (medium_manager_->isBleAvailable()) { + if (mediums_->GetBle().IsAvailable()) { mediums.push_back(proto::connections::BLE); } return mediums; } -template -proto::connections::Medium -P2PStarPCPHandler::getDefaultUpgradeMedium() { +proto::connections::Medium P2pStarPcpHandler::GetDefaultUpgradeMedium() { return proto::connections::Medium::WIFI_HOTSPOT; } -template -bool P2PStarPCPHandler::canSendOutgoingConnection( - Ptr > client_proxy) { +bool P2pStarPcpHandler::CanSendOutgoingConnection(ClientProxy* client) const { // For star, we can only send an outgoing connection while we have no other // connections. - return !this->hasOutgoingConnections(client_proxy) && - !this->hasIncomingConnections(client_proxy); + return !this->HasOutgoingConnections(client) && + !this->HasIncomingConnections(client); } -template -bool P2PStarPCPHandler::canReceiveIncomingConnection( - Ptr > client_proxy) { +bool P2pStarPcpHandler::CanReceiveIncomingConnection( + ClientProxy* client) const { // For star, we can only receive an incoming connection if we've sent no // outgoing connections. - return !this->hasOutgoingConnections(client_proxy); + return !this->HasOutgoingConnections(client); } } // namespace connections diff --git a/cpp/core/internal/p2p_star_pcp_handler.h b/cpp/core/internal/p2p_star_pcp_handler.h index b16a5a48..caa5fc61 100644 --- a/cpp/core/internal/p2p_star_pcp_handler.h +++ b/cpp/core/internal/p2p_star_pcp_handler.h @@ -3,57 +3,42 @@ #include -#include "core/internal/bandwidth_upgrade_manager.h" #include "core/internal/client_proxy.h" #include "core/internal/endpoint_channel_manager.h" #include "core/internal/endpoint_manager.h" -#include "core/internal/medium_manager.h" #include "core/internal/p2p_cluster_pcp_handler.h" #include "core/internal/pcp.h" #include "core/strategy.h" -#include "platform/ptr.h" namespace location { namespace nearby { namespace connections { -// Concrete implementation of the PCPHandler for the P2P_STAR PCP. This PCP is +// Concrete implementation of the PcpHandler for the P2P_STAR PCP. This Pcp is // for mediums that have one server with (potentially) many clients; all mediums -// in P2P_CLUSTER are valid for P2P_STAR, but not all mediums in P2P_STAR and +// in P2P_CLUSTER are valid for P2P_STAR, but not all mediums in P2P_STAR are // valid for P2P_CLUSTER. // -//

Currently, this implementation advertises/discovers over BLE and Bluetooth -// and connects over Bluetooth, eventually upgrading to a Wifi Hotspot. -template -class P2PStarPCPHandler : public P2PClusterPCPHandler { +// Currently, this implementation advertises/discovers over Bluetooth +// and connects over Bluetooth. +class P2pStarPcpHandler : public P2pClusterPcpHandler { public: - P2PStarPCPHandler(Ptr > medium_manager, - Ptr > endpoint_manager, - Ptr endpoint_channel_manager, - Ptr bandwidth_upgrade_manager); - ~P2PStarPCPHandler() override; - - Strategy getStrategy() override; - PCP::Value getPCP() override; + P2pStarPcpHandler(Mediums& mediums, EndpointManager& endpoint_manager, + EndpointChannelManager& channel_manager, + BwuManager& bwu_manager, + Pcp pcp = Pcp::kP2pStar); protected: - std::vector getConnectionMediumsByPriority() + std::vector GetConnectionMediumsByPriority() override; - proto::connections::Medium getDefaultUpgradeMedium() override; + proto::connections::Medium GetDefaultUpgradeMedium() override; - bool canSendOutgoingConnection( - Ptr > client_proxy) override; - bool canReceiveIncomingConnection( - Ptr > client_proxy) override; - - private: - Ptr > medium_manager_; + bool CanSendOutgoingConnection(ClientProxy* client) const override; + bool CanReceiveIncomingConnection(ClientProxy* client) const override; }; } // namespace connections } // namespace nearby } // namespace location -#include "core/internal/p2p_star_pcp_handler.cc" - #endif // CORE_INTERNAL_P2P_STAR_PCP_HANDLER_H_ diff --git a/cpp/core/internal/payload_manager.cc b/cpp/core/internal/payload_manager.cc index fd749499..1e5c578c 100644 --- a/cpp/core/internal/payload_manager.cc +++ b/cpp/core/internal/payload_manager.cc @@ -1,639 +1,305 @@ #include "core/internal/payload_manager.h" #include +#include +#include +#include #include -#include "platform/synchronized.h" +#include "core/internal/internal_payload_factory.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/mutex_lock.h" +#include "platform/public/single_thread_executor.h" +#include "platform/public/system_clock.h" +#include "absl/memory/memory.h" +#include "absl/strings/str_cat.h" +#include "absl/time/time.h" namespace location { namespace nearby { namespace connections { -namespace payload_manager { +// C++14 requires to declare this. +// TODO(apolyudov): remove when migration to c++17 is possible. +constexpr const absl::Duration PayloadManager::kWaitCloseTimeout; -template -void eraseOwnedPtrFromMap(std::map >& m, const K& k) { - typename std::map >::iterator it = m.find(k); - if (it != m.end()) { - it->second.destroy(); - m.erase(it); +bool PayloadManager::SendPayloadLoop( + ClientProxy* client, PendingPayload& pending_payload, + PayloadTransferFrame::PayloadHeader& payload_header, + std::int64_t& next_chunk_offset) { + // in lieu of structured binding: + auto pair = GetAvailableAndUnavailableEndpoints(pending_payload); + const EndpointIds& available_endpoint_ids = + EndpointsToEndpointIds(pair.first); + const Endpoints& unavailable_endpoints = pair.second; + + NEARBY_LOG(INFO, + "SendPayloadLoop: Available: { %s }; Unavailable: { %s }; " + "payload_id=%" PRIX64 "; self=%p", + ToString(available_endpoint_ids).c_str(), + ToString(unavailable_endpoints).c_str(), + static_cast(payload_header.id()), this); + + // First, handle any non-available endpoints. + for (const auto& endpoint : unavailable_endpoints) { + HandleFinishedOutgoingPayload( + client, {endpoint->id}, payload_header, next_chunk_offset, + EndpointInfoStatusToPayloadStatus(endpoint->status.Get())); + } + + // Update the still-active recipients of this payload. + if (available_endpoint_ids.empty()) { + NEARBY_LOG(INFO, "No more available endpoints: payload_id=%" PRIX64, + pending_payload.GetInternalPayload()->GetId()); + return false; + } + + // Check if the payload has been cancelled by the client and, if so, + // notify the remaining recipients. + if (pending_payload.IsLocallyCanceled()) { + NEARBY_LOG(INFO, "Payload canceled locally: payload_id=%" PRIX64, + pending_payload.GetInternalPayload()->GetId()); + HandleFinishedOutgoingPayload( + client, available_endpoint_ids, payload_header, next_chunk_offset, + proto::connections::PayloadStatus::LOCAL_CANCELLATION); + return false; + } + + // Update the current offsets for all endpoints still active for this + // payload. For the sake of accuracy, we update the pending payload here + // because it's after all payload terminating events are handled, but + // right before we actually start detaching the next chunk. + for (const auto& endpoint_id : available_endpoint_ids) { + pending_payload.SetOffsetForEndpoint(endpoint_id, next_chunk_offset); + } + + // This will block if there is no data to transfer. + // It will resume when new data arrives, or if Close() is called. + ByteArray next_chunk = + pending_payload.GetInternalPayload()->DetachNextChunk(); + if (shutdown_.Get()) return false; + // Save chunk size. We'll need it after we move next_chunk. + auto next_chunk_size = next_chunk.size(); + if (!next_chunk_size && + pending_payload.GetInternalPayload()->GetTotalSize() > 0 && + pending_payload.GetInternalPayload()->GetTotalSize() < + next_chunk_offset) { + NEARBY_LOG(INFO, "Payload xfer failed: payload_id=%" PRIX64, + pending_payload.GetInternalPayload()->GetId()); + HandleFinishedOutgoingPayload( + client, available_endpoint_ids, payload_header, next_chunk_offset, + proto::connections::PayloadStatus::LOCAL_ERROR); + return false; + } + + PayloadTransferFrame::PayloadChunk payload_chunk( + CreatePayloadChunk(next_chunk_offset, std::move(next_chunk))); + const EndpointIds& failed_endpoint_ids = endpoint_manager_->SendPayloadChunk( + payload_header, payload_chunk, available_endpoint_ids); + // Check whether at least one endpoint failed. + if (!failed_endpoint_ids.empty()) { + NEARBY_LOG(INFO, + "Payload xfer: endpoints failed: payload_id=%" PRIX64 + "; ids={%s}", + static_cast(payload_header.id()), + ToString(failed_endpoint_ids).c_str()); + HandleFinishedOutgoingPayload( + client, failed_endpoint_ids, payload_header, next_chunk_offset, + proto::connections::PayloadStatus::ENDPOINT_IO_ERROR); + } + + // Check whether at least one endpoint succeeded -- if they all failed, + // we'll just go right back to the top of the loop and break out when + // availableEndpointIds is re-synced and found to be empty at that point. + if (failed_endpoint_ids.size() < available_endpoint_ids.size()) { + for (const auto& endpoint_id : available_endpoint_ids) { + if (std::find(failed_endpoint_ids.begin(), failed_endpoint_ids.end(), + endpoint_id) == failed_endpoint_ids.end()) { + HandleSuccessfulOutgoingChunk( + client, endpoint_id, payload_header, payload_chunk.flags(), + payload_chunk.offset(), payload_chunk.body().size()); + } + } + + next_chunk_offset += next_chunk_size; + + if (!next_chunk_size) { + // That was the last chunk, we're outta here. + NEARBY_LOG( + INFO, "Payload xfer done: payload_id=%" PRIX64 "; size=%" PRId64, + pending_payload.GetInternalPayload()->GetId(), next_chunk_offset); + return false; + } + } + + return true; +} + +std::pair +PayloadManager::GetAvailableAndUnavailableEndpoints( + const PendingPayload& pending_payload) { + Endpoints available; + Endpoints unavailable; + for (auto* endpoint_info : pending_payload.GetEndpoints()) { + NEARBY_LOG(INFO, "EndpointInfo: %p; id=%s; status=%d", endpoint_info, + endpoint_info->id.c_str(), endpoint_info->status.Get()); + if (endpoint_info->status.Get() == + PayloadManager::EndpointInfo::Status::kAvailable) { + available.push_back(endpoint_info); + } else { + unavailable.push_back(endpoint_info); + } + } + return std::make_pair(std::move(available), std::move(unavailable)); +} + +PayloadManager::EndpointIds PayloadManager::EndpointsToEndpointIds( + const Endpoints& endpoints) { + EndpointIds endpoint_ids; + endpoint_ids.reserve(endpoints.size()); + for (const auto& item : endpoints) { + if (item) { + endpoint_ids.emplace_back(item->id); + } + } + return endpoint_ids; +} + +std::string PayloadManager::ToString(const Endpoints& endpoints) { + std::string endpoints_string = absl::StrCat(endpoints.size(), ": "); + bool first = true; + for (const auto& item : endpoints) { + if (first) { + absl::StrAppend(&endpoints_string, item->id); + first = false; + } else { + absl::StrAppend(&endpoints_string, ", ", item->id); + } + } + return endpoints_string; +} + +std::string PayloadManager::ToString(const EndpointIds& endpoint_ids) { + std::string endpoints_string = absl::StrCat(endpoint_ids.size(), ": "); + bool first = true; + for (const auto& id : endpoint_ids) { + if (first) { + absl::StrAppend(&endpoints_string, id); + first = false; + } else { + absl::StrAppend(&endpoints_string, ", ", id); + } + } + return endpoints_string; +} + +// Creates and starts tracking a PendingPayload for this Payload. +Payload::Id PayloadManager::CreateOutgoingPayload( + Payload payload, const EndpointIds& endpoint_ids) { + auto internal_payload{CreateOutgoingInternalPayload(std::move(payload))}; + Payload::Id payload_id = internal_payload->GetId(); + NEARBY_LOG(INFO, "CreateOutgoingPayload: payload_id=%" PRIX64, payload_id); + MutexLock lock(&mutex_); + pending_payloads_.StartTrackingPayload( + payload_id, absl::make_unique(std::move(internal_payload), + endpoint_ids, + /*is_incoming=*/false)); + + return payload_id; +} + +PayloadManager::PayloadManager(EndpointManager& endpoint_manager) + : endpoint_manager_(&endpoint_manager) { + handle_ = endpoint_manager_->RegisterFrameProcessor(V1Frame::PAYLOAD_TRANSFER, + this); +} + +void PayloadManager::CancelAllPayloads() { + NEARBY_LOG(INFO, "PayloadManager: canceling payloads; self=%p", this); + { + MutexLock lock(&mutex_); + int pending_outgoing_payloads = 0; + for (const auto& pending_id : pending_payloads_.GetAllPayloads()) { + auto* pending = pending_payloads_.GetPayload(pending_id); + if (!pending->IsIncoming()) pending_outgoing_payloads++; + pending->MarkLocallyCanceled(); + pending->Close(); // To unblock the sender thread, if there is no data. + } + if (pending_outgoing_payloads) { + shutdown_barrier_ = + absl::make_unique(pending_outgoing_payloads); + } + } + + if (shutdown_barrier_) { + NEARBY_LOG(INFO, + "PayloadManager: waiting for pending outgoing payloads; self=%p", + this); + shutdown_barrier_->Await(); } } -template -class SendPayloadRunnable : public Runnable { - public: - SendPayloadRunnable(Ptr > payload_manager, - Ptr > client_proxy, - const std::vector& endpoint_ids, - ConstPtr payload) - : payload_manager_(payload_manager), - client_proxy_(client_proxy), - endpoint_ids_(endpoint_ids), - payload_(payload) {} - - void run() override { - // If successfully created, pending_payload is owned by - // PayloadManager::pending_payloads_ until - // PayloadManager::PendingPayloads::stopTrackingPayload() is invoked. - Ptr::PendingPayload> pending_payload( - createOutgoingPayload(payload_.release(), endpoint_ids_)); - if (pending_payload.isNull()) { - // TODO(tracyzhou): Add logging. - return; - } - - ScopedPtr > payload_header( - payload_manager_->createPayloadHeader( - ConstifyPtr(pending_payload->getInternalPayload()))); - - payload_manager_->send_payload_loop_runner_->loop( - MakePtr(new LoopCallable(payload_manager_, client_proxy_, - pending_payload, payload_header.get()))); - } - - private: - class LoopCallable : public Callable { - public: - LoopCallable( - Ptr > payload_manager, - Ptr > client_proxy, - Ptr::PendingPayload> pending_payload, - ConstPtr payload_header) - : next_chunk_offset_(0), - payload_manager_(payload_manager), - client_proxy_(client_proxy), - pending_payload_(pending_payload), - payload_header_(payload_header) {} - - ExceptionOr call() override { - AvailableAndUnavailableEndpoints available_and_unavailable_endpoints = - getAvailableAndUnavailableEndpoints(ConstifyPtr(pending_payload_)); - const UnavailableEndpoints& unavailable_endpoints = - available_and_unavailable_endpoints.second; - - // First, handle any non-available endpoints. - for (typename UnavailableEndpoints::const_iterator it = - unavailable_endpoints.begin(); - it != unavailable_endpoints.end(); it++) { - Ptr::EndpointInfo> endpoint_info = - *it; - payload_manager_->handleFinishedOutgoingPayload( - client_proxy_, std::vector(1, endpoint_info->getId()), - *payload_header_, next_chunk_offset_, - PayloadManager::endpointInfoStatusToPayloadStatus( - endpoint_info->getStatus())); - } - - // Update the still-active recipients of this payload. - const AvailableEndpointIds& available_endpoint_ids = - available_and_unavailable_endpoints.first; - if (available_endpoint_ids.empty()) { - // TODO(tracyzhou): Add logging. - return ExceptionOr(false); - } - - // Check if the payload has been cancelled by the client and, if so, - // notify the remaining recipients. - if (pending_payload_->isLocallyCanceled()) { - // TODO(tracyzhou): Add logging. - payload_manager_->handleFinishedOutgoingPayload( - client_proxy_, available_endpoint_ids, *payload_header_, - next_chunk_offset_, - proto::connections::PayloadStatus::LOCAL_CANCELLATION); - return ExceptionOr(false); - } - - // Update the current offsets for all endpoints still active for this - // payload. For the sake of accuracy, we update the pending payload here - // because it's after all payload terminating events are handled, but - // right before we actually start detaching the next chunk. - for (AvailableEndpointIds::const_iterator it = - available_endpoint_ids.begin(); - it != available_endpoint_ids.end(); it++) { - const string& endpoint_id = *it; - pending_payload_->setOffsetForEndpoint(endpoint_id, next_chunk_offset_); - } - - ExceptionOr > next_chunk = - pending_payload_->getInternalPayload()->detachNextChunk(); - if (!next_chunk.ok()) { - if (Exception::IO == next_chunk.exception()) { - // TODO(tracyzhou): Add logging. - payload_manager_->handleFinishedOutgoingPayload( - client_proxy_, available_endpoint_ids, *payload_header_, - next_chunk_offset_, - proto::connections::PayloadStatus::LOCAL_ERROR); - return ExceptionOr(false); - } - } - - ScopedPtr > scoped_next_chunk(next_chunk.result()); - ScopedPtr > payload_chunk( - payload_manager_->createPayloadChunk(next_chunk_offset_, - scoped_next_chunk.get())); - std::vector failed_endpoint_ids = - payload_manager_->endpoint_manager_->sendPayloadChunk( - *payload_header_, *payload_chunk, available_endpoint_ids); - - // Check whether at least one endpoint failed. - if (!failed_endpoint_ids.empty()) { - payload_manager_->handleFinishedOutgoingPayload( - client_proxy_, failed_endpoint_ids, *payload_header_, - next_chunk_offset_, - proto::connections::PayloadStatus::ENDPOINT_IO_ERROR); - } - - // Check whether at least one endpoint succeeded -- if they all failed, - // we'll just go right back to the top of the loop and break out when - // availableEndpointIds is re-synced and found to be empty at that point. - if (failed_endpoint_ids.size() < available_endpoint_ids.size()) { - for (std::vector::const_iterator it = - available_endpoint_ids.begin(); - it != available_endpoint_ids.end(); it++) { - const string& endpoint_id = *it; - if (std::find(failed_endpoint_ids.begin(), failed_endpoint_ids.end(), - endpoint_id) == failed_endpoint_ids.end()) { - payload_manager_->handleSuccessfulOutgoingChunk( - client_proxy_, endpoint_id, *payload_header_, - payload_chunk->flags(), payload_chunk->offset(), - payload_chunk->body().size()); - } - } - - // TODO(tracyzhou): Add logging. - if (scoped_next_chunk.isNull()) { - // That was the last chunk, we're outta here. - return ExceptionOr(false); - } - - next_chunk_offset_ += scoped_next_chunk->size(); - } - return ExceptionOr(true); - } - - private: - typedef std::vector AvailableEndpointIds; - typedef std::vector::EndpointInfo> > - UnavailableEndpoints; - typedef std::pair - AvailableAndUnavailableEndpoints; - - // Splits the endpoints for this payload by availability. Returns a pair of - // lists, with the first being the list of still-available endpoint IDs and - // the second the list of EndpointInfos for unavailable endpoints. - static AvailableAndUnavailableEndpoints getAvailableAndUnavailableEndpoints( - ConstPtr::PendingPayload> - pending_payload) { - AvailableEndpointIds available_endpoint_ids; - UnavailableEndpoints unavailable_endpoints; - std::vector::EndpointInfo> > - endpoints = pending_payload->getEndpoints(); - for (typename std::vector::EndpointInfo> >::const_iterator it = - endpoints.begin(); - it != endpoints.end(); it++) { - Ptr::EndpointInfo> endpoint_info = - *it; - if (PayloadManager::EndpointInfo::Status::AVAILABLE == - endpoint_info->getStatus()) { - available_endpoint_ids.push_back(endpoint_info->getId()); - } else { - unavailable_endpoints.push_back(endpoint_info); - } - } - return std::make_pair(available_endpoint_ids, unavailable_endpoints); - } - - // Keep track of the chunk offset across iterations. - std::int64_t next_chunk_offset_; - Ptr > payload_manager_; - Ptr > client_proxy_; - Ptr::PendingPayload> pending_payload_; - ConstPtr payload_header_; - }; - - // Creates and starts tracking a PendingPayload for this Payload. Returns null - // if unable to create the InternalPayload. - Ptr::PendingPayload> createOutgoingPayload( - ConstPtr payload, const std::vector& endpoint_ids) { - ScopedPtr > scoped_payload(payload); - - ScopedPtr > internal_payload( - payload_manager_->internal_payload_factory_->createOutgoing( - scoped_payload.release())); - if (internal_payload.isNull()) { - return Ptr::PendingPayload>(); - } - - std::int64_t payload_id = internal_payload->getId(); - ScopedPtr::PendingPayload> > - pending_payload( - PayloadManager::PendingPayload::createOutgoing( - internal_payload.release(), endpoint_ids)); - payload_manager_->pending_payloads_->startTrackingPayload( - payload_id, pending_payload.release()); - - return payload_manager_->pending_payloads_->getPayload(payload_id); - } - - Ptr > payload_manager_; - Ptr > client_proxy_; - std::vector endpoint_ids_; - ScopedPtr > payload_; -}; - -template -class ProcessEndpointDisconnectionRunnable : public Runnable { - public: - ProcessEndpointDisconnectionRunnable( - Ptr > payload_manager, - Ptr > client_proxy, const string& endpoint_id, - Ptr process_disconnection_barrier) - : payload_manager_(payload_manager), - client_proxy_(client_proxy), - endpoint_id_(endpoint_id), - process_disconnection_barrier_(process_disconnection_barrier) {} - - void run() override { - std::vector endpoints_to_remove(1, endpoint_id_); - - // Iterate through all our payloads and look for payloads associated with - // this endpoint. - std::vector::PendingPayload> > - pending = payload_manager_->pending_payloads_->getAllPayloads(); - for (typename std::vector::PendingPayload> >::const_iterator it = pending.begin(); - it != pending.end(); it++) { - Ptr::PendingPayload> pending_payload = - *it; - Ptr::EndpointInfo> endpoint_info = - pending_payload->getEndpoint(endpoint_id_); - if (endpoint_info.isNull()) { - continue; - } - - // Stop tracking the endpoint for this payload. - pending_payload->removeEndpoints(endpoints_to_remove); - - std::int64_t payload_id = pending_payload->getId(); - std::int64_t payload_total_size = - pending_payload->getInternalPayload()->getTotalSize(); - - // If no endpoints are left for this payload, stop tracking it and close - // it. - if (pending_payload->getEndpoints().empty()) { - pending_payload = - payload_manager_->pending_payloads_->stopTrackingPayload( - pending_payload->getId()); - pending_payload->close(); - pending_payload.destroy(); - } - - // Create the payload transfer update. - PayloadTransferUpdate update( - payload_id, PayloadTransferUpdate::Status::FAILURE, - payload_total_size, endpoint_info->getOffset()); - - // Send a client notification of a payload transfer failure. - client_proxy_->onPayloadTransferUpdate(endpoint_id_, update); - } - - process_disconnection_barrier_->countDown(); - } - - private: - Ptr > payload_manager_; - Ptr > client_proxy_; - const string endpoint_id_; - Ptr process_disconnection_barrier_; -}; - -template -class SendClientCallbacksForFinishedOutgoingPayloadRunnable : public Runnable { - public: - SendClientCallbacksForFinishedOutgoingPayloadRunnable( - Ptr > payload_manager, - Ptr > client_proxy, - const std::vector& finished_endpoint_ids, - const PayloadTransferFrame::PayloadHeader& payload_header, - std::int64_t num_bytes_successfully_transferred, - proto::connections::PayloadStatus status) - : payload_manager_(payload_manager), - client_proxy_(client_proxy), - finished_endpoint_ids_(finished_endpoint_ids), - payload_header_(payload_header), - num_bytes_successfully_transferred_(num_bytes_successfully_transferred), - status_(status) {} - - void run() override { - // Make sure we're still tracking this payload. - Ptr::PendingPayload> pending_payload = - payload_manager_->pending_payloads_->getPayload(payload_header_.id()); - if (pending_payload.isNull()) { - return; - } - - PayloadTransferUpdate update( - payload_header_.id(), - PayloadManager::payloadStatusToTransferUpdateStatus(status_), - payload_header_.total_size(), num_bytes_successfully_transferred_); - for (std::vector::const_iterator it = - finished_endpoint_ids_.begin(); - it != finished_endpoint_ids_.end(); it++) { - const string& endpoint_id = *it; - - // Skip sending notifications if we have stopped tracking this endpoint. - if (pending_payload->getEndpoint(endpoint_id).isNull()) { - continue; - } - - // Notify the client. - client_proxy_->onPayloadTransferUpdate(endpoint_id, update); - } - - // Remove these endpoints from our tracking list for this payload. - pending_payload->removeEndpoints(finished_endpoint_ids_); - - // Close the payload and stop tracking it if no endpoints remain. - if (pending_payload->getEndpoints().empty()) { - pending_payload = - payload_manager_->pending_payloads_->stopTrackingPayload( - payload_header_.id()); - pending_payload->close(); - pending_payload.destroy(); - } - } - - private: - Ptr > payload_manager_; - Ptr > client_proxy_; - const std::vector finished_endpoint_ids_; - const PayloadTransferFrame::PayloadHeader payload_header_; - const std::int64_t num_bytes_successfully_transferred_; - const proto::connections::PayloadStatus status_; -}; - -template -class SendClientCallbacksForFinishedIncomingPayloadRunnable : public Runnable { - public: - SendClientCallbacksForFinishedIncomingPayloadRunnable( - Ptr > payload_manager, - Ptr > client_proxy, const string& endpoint_id, - const PayloadTransferFrame::PayloadHeader& payload_header, - std::int64_t offset_bytes, proto::connections::PayloadStatus status) - : payload_manager_(payload_manager), - client_proxy_(client_proxy), - endpoint_id_(endpoint_id), - payload_header_(payload_header), - offset_bytes_(offset_bytes), - status_(status) {} - - void run() override { - // Make sure we're still tracking this payload. - Ptr::PendingPayload> pending_payload = - payload_manager_->pending_payloads_->getPayload(payload_header_.id()); - if (pending_payload.isNull()) { - return; - } - - // Unless we never started tracking this payload (meaning we failed to even - // create the InternalPayload), notify the client (and close it). - PayloadTransferUpdate update( - payload_header_.id(), - PayloadManager::payloadStatusToTransferUpdateStatus(status_), - payload_header_.total_size(), offset_bytes_); - payload_manager_->notifyClientOfIncomingPayloadTransferUpdate( - client_proxy_, endpoint_id_, update, /*done_with_payload=*/true); - } - - private: - Ptr > payload_manager_; - Ptr > client_proxy_; - const string endpoint_id_; - const PayloadTransferFrame::PayloadHeader payload_header_; - const std::int64_t offset_bytes_; - const proto::connections::PayloadStatus status_; -}; - -template -class HandleSuccessfulOutgoingChunkRunnable : public Runnable { - public: - HandleSuccessfulOutgoingChunkRunnable( - Ptr > payload_manager, - Ptr > client_proxy, const string& endpoint_id, - const PayloadTransferFrame::PayloadHeader& payload_header, - std::int32_t payload_chunk_flags, std::int64_t payload_chunk_offset, - std::int64_t payload_chunk_body_size) - : payload_manager_(payload_manager), - client_proxy_(client_proxy), - endpoint_id_(endpoint_id), - payload_header_(payload_header), - payload_chunk_flags_(payload_chunk_flags), - payload_chunk_offset_(payload_chunk_offset), - payload_chunk_body_size_(payload_chunk_body_size) {} - - void run() override { - // Make sure we're still tracking this payload and its associated endpoint. - Ptr::PendingPayload> pending_payload = - payload_manager_->pending_payloads_->getPayload(payload_header_.id()); - if (pending_payload.isNull() || - pending_payload->getEndpoint(endpoint_id_).isNull()) { - return; - } - - // TODO(reznor): The fact that we've sent total_size bytes (which we will - // always know 1 frame before we get the SUCCESS frame), also tells us this - // is the last chunk - should we add those smarts, or just be simple and - // always have the last IN_PROGRESS have the same numbers as the following - // SUCCESS? I prefer the simplicity, but it'll look stupid if we send all - // the bytes and then remain hanging because the remote device disconnected - // at just that point, so at least consider injecting the smarts. - // TODO(reznor): Should we check whether payload_header.total_size == - // payload_chunk.offset? - bool is_last_chunk = (payload_chunk_flags_ & - PayloadTransferFrame::PayloadChunk::LAST_CHUNK) != 0; - PayloadTransferUpdate update( - payload_header_.id(), - is_last_chunk ? PayloadTransferUpdate::Status::SUCCESS - : PayloadTransferUpdate::Status::IN_PROGRESS, - payload_header_.total_size(), - is_last_chunk ? payload_chunk_offset_ - : payload_chunk_offset_ + payload_chunk_body_size_); - - // Notify the client. - client_proxy_->onPayloadTransferUpdate(endpoint_id_, update); - - if (is_last_chunk) { - // Stop tracking this endpoint. - pending_payload->removeEndpoints(std::vector(1, endpoint_id_)); - - // Close the payload and stop tracking it if no endpoints remain. - if (pending_payload->getEndpoints().empty()) { - pending_payload = - payload_manager_->pending_payloads_->stopTrackingPayload( - payload_header_.id()); - pending_payload->close(); - pending_payload.destroy(); - } - } - } - - private: - Ptr > payload_manager_; - Ptr > client_proxy_; - const string endpoint_id_; - const PayloadTransferFrame::PayloadHeader payload_header_; - const std::int32_t payload_chunk_flags_; - const std::int64_t payload_chunk_offset_; - const std::int64_t payload_chunk_body_size_; -}; - -template -class HandleSuccessfulIncomingChunkRunnable : public Runnable { - public: - HandleSuccessfulIncomingChunkRunnable( - Ptr > payload_manager, - Ptr > client_proxy, const string& endpoint_id, - const PayloadTransferFrame::PayloadHeader& payload_header, - std::int32_t payload_chunk_flags, std::int64_t payload_chunk_offset, - std::int64_t payload_chunk_body_size) - : payload_manager_(payload_manager), - client_proxy_(client_proxy), - endpoint_id_(endpoint_id), - payload_header_(payload_header), - payload_chunk_flags_(payload_chunk_flags), - payload_chunk_offset_(payload_chunk_offset), - payload_chunk_body_size_(payload_chunk_body_size) {} - - void run() override { - // Make sure we're still tracking this payload. - Ptr::PendingPayload> pending_payload = - payload_manager_->pending_payloads_->getPayload(payload_header_.id()); - if (pending_payload.isNull()) { - return; - } - - // TODO(reznor): The fact that we've received total_size bytes (which we - // will always know 1 frame before we get the SUCCESS frame), also tells us - // this is the last chunk - should we add those smarts, or just be simple - // and always have the last IN_PROGRESS have the same numbers as the - // following SUCCESS? I prefer the simplicity, but it'll look stupid if we - // get all the bytes and then remain hanging because the remote device - // disconnected at just that point, so at least consider injecting the - // smarts. - bool is_last_chunk = (payload_chunk_flags_ & - PayloadTransferFrame::PayloadChunk::LAST_CHUNK) != 0; - PayloadTransferUpdate update( - payload_header_.id(), - is_last_chunk ? PayloadTransferUpdate::Status::SUCCESS - : PayloadTransferUpdate::Status::IN_PROGRESS, - payload_header_.total_size(), - is_last_chunk ? payload_chunk_offset_ - : payload_chunk_offset_ + payload_chunk_body_size_); - - // Notify the client of this update. - payload_manager_->notifyClientOfIncomingPayloadTransferUpdate( - client_proxy_, endpoint_id_, update, is_last_chunk); - } - - private: - Ptr > payload_manager_; - Ptr > client_proxy_; - const string endpoint_id_; - const PayloadTransferFrame::PayloadHeader payload_header_; - const std::int32_t payload_chunk_flags_; - const std::int64_t payload_chunk_offset_; - const std::int64_t payload_chunk_body_size_; -}; - -template -class ProcessDataPacketRunnable : public Runnable { - public: - ProcessDataPacketRunnable(Ptr > to_client_proxy, - const string& from_endpoint_id, - ConstPtr payload) - : to_client_proxy_(to_client_proxy), - from_endpoint_id_(from_endpoint_id), - payload_(payload) {} - - void run() override { - to_client_proxy_->onPayloadReceived(from_endpoint_id_, payload_.release()); - } - - private: - Ptr > to_client_proxy_; - const string from_endpoint_id_; - ScopedPtr > payload_; -}; - -} // namespace payload_manager - -template -PayloadManager::PayloadManager( - Ptr > endpoint_manager) - : internal_payload_factory_(new InternalPayloadFactory()), - send_payload_loop_runner_(new LoopRunner("sendPayload")), - pending_payloads_(new PendingPayloads()), - bytes_payload_executor_(Platform::createSingleThreadExecutor()), - file_payload_executor_(Platform::createSingleThreadExecutor()), - stream_payload_executor_(Platform::createSingleThreadExecutor()), - payload_status_update_executor_(Platform::createSingleThreadExecutor()), - endpoint_manager_(endpoint_manager) { - endpoint_manager_->registerIncomingOfflineFrameProcessor( - V1Frame::PAYLOAD_TRANSFER, std::static_pointer_cast< - typename EndpointManager::IncomingOfflineFrameProcessor>( - self_)); +void PayloadManager::DisconnectFromEndpointManager() { + if (shutdown_.Set(true)) return; + // Unregister ourselves from the FrameProcessors. + endpoint_manager_->UnregisterFrameProcessor(V1Frame::PAYLOAD_TRANSFER, + handle_, true); } -template -PayloadManager::~PayloadManager() { - // TODO(reznor): - // logger.atDebug().log("Initiating shutdown of PayloadManager"); - - // Unregister ourselves from the IncomingOfflineFrameProcessors. - endpoint_manager_->unregisterIncomingOfflineFrameProcessor( - V1Frame::CONNECTION_RESPONSE, std::static_pointer_cast< - typename EndpointManager::IncomingOfflineFrameProcessor>( - self_)); - - // Stop all the ongoing Runnables (as gracefully as possible). - payload_status_update_executor_->shutdown(); - bytes_payload_executor_->shutdown(); - file_payload_executor_->shutdown(); - stream_payload_executor_->shutdown(); - - typedef Ptr::PendingPayload> - PtrPendingPayload; +PayloadManager::~PayloadManager() { + NEARBY_LOG(INFO, "PayloadManager: going down; self=%p", this); + DisconnectFromEndpointManager(); + CancelAllPayloads(); + NEARBY_LOG(INFO, "PayloadManager: turn down payload executors; self=%p", + this); + bytes_payload_executor_.Shutdown(); + stream_payload_executor_.Shutdown(); + file_payload_executor_.Shutdown(); + CountDownLatch stop_latch(1); // Clear our tracked pending payloads. - std::vector pending = pending_payloads_->getAllPayloads(); - for (typename std::vector::const_iterator it = - pending.begin(); - it != pending.end(); it++) { - PtrPendingPayload pending_payload = - pending_payloads_->stopTrackingPayload((*it)->getId()); - pending_payload->close(); - pending_payload.destroy(); - } + RunOnStatusUpdateThread([this, &stop_latch]() { + NEARBY_LOG(INFO, "PayloadManager: stop tracking payloads; self=%p", this); + MutexLock lock(&mutex_); + for (const auto& pending_id : pending_payloads_.GetAllPayloads()) { + pending_payloads_.StopTrackingPayload(pending_id); + } + stop_latch.CountDown(); + }); + stop_latch.Await(); - // TODO(reznor): - // logger.atVerbose().log("PayloadManager has shut down."); + NEARBY_LOG(INFO, "PayloadManager: turn down notification executor; self=%p", + this); + // Stop all the ongoing Runnables (as gracefully as possible). + payload_status_update_executor_.Shutdown(); + + NEARBY_LOG(INFO, "PayloadManager: down; self=%p", this); } -template -void PayloadManager::sendPayload( - Ptr > client_proxy, - const std::vector& endpoint_ids, ConstPtr payload) { - Ptr send_payload_executor = - getOutgoingPayloadExecutor(payload->getType()); - // The send_payload_executor will be null if the payload is of a type - // we cannot work with. This should never be reached since the - // ServiceControllerRouter has already checked whether or not we can work with - // this Payload type. - ScopedPtr > scoped_payload(payload); - if (send_payload_executor.isNull()) { - // TODO(tracyzhou): Add logging. +bool PayloadManager::NotifyShutdown() { + MutexLock lock(&mutex_); + if (!shutdown_.Get()) return false; + if (!shutdown_barrier_) return false; + NEARBY_LOG(INFO, "PayloadManager [shutdown mode]"); + shutdown_barrier_->CountDown(); + return true; +} + +void PayloadManager::SendPayload(ClientProxy* client, + const EndpointIds& endpoint_ids, + Payload payload) { + if (shutdown_.Get()) return; + NEARBY_LOG(INFO, "SendPayload: endpoint_ids={%s}", + ToString(endpoint_ids).c_str()); + auto executor = GetOutgoingPayloadExecutor(payload.GetType()); + // The |executor| will be null if the payload is of a type we cannot work + // with. This should never be reached since the ServiceControllerRouter has + // already checked whether or not we can work with this Payload type. + if (!executor) { + NEARBY_LOG(INFO, + "PayloadManager::SendPayload: unsupported: id=%" PRIX64 + ", type=%d", + payload.GetId(), payload.GetType()); return; } @@ -641,87 +307,143 @@ void PayloadManager::sendPayload( // other payload of the same type from even starting until this one is // completely done with. If we ever want to provide isolation across // ClientProxy objects this will need to be significantly re-architected. - enqueueOutgoingPayload( - send_payload_executor, - MakePtr(new payload_manager::SendPayloadRunnable( - self_, client_proxy, endpoint_ids, - scoped_payload.release()))); - // TODO(tracyzhou): Add logging. + Payload::Type payload_type = payload.GetType(); + Payload::Id payload_id = + CreateOutgoingPayload(std::move(payload), endpoint_ids); + executor->Execute([this, client, endpoint_ids, payload_id]() { + if (shutdown_.Get()) return; + PendingPayload* pending_payload = GetPayload(payload_id); + if (!pending_payload) return; + auto* internal_payload = pending_payload->GetInternalPayload(); + if (!internal_payload) return; + PayloadTransferFrame::PayloadHeader payload_header{ + CreatePayloadHeader(*internal_payload)}; + bool should_continue = true; + std::int64_t next_chunk_offset = 0; + while (should_continue && !shutdown_.Get()) { + should_continue = SendPayloadLoop(client, *pending_payload, + payload_header, next_chunk_offset); + } + RunOnStatusUpdateThread( + [this, payload_id]() { DestroyPendingPayload(payload_id); }); + }); + NEARBY_LOG(INFO, + "PayloadManager: xfer scheduled: self=%p; id=%" PRIX64 ", type=%d", + this, payload_id, payload_type); } -template -Status::Value PayloadManager::cancelPayload( - Ptr > client_proxy, std::int64_t payload_id) { - Ptr::PendingPayload> canceled_payload = - pending_payloads_->getPayload(payload_id); - if (canceled_payload.isNull()) { - // TODO(tracyzhou): Add logging. - return Status::PAYLOAD_UNKNOWN; +PayloadManager::PendingPayload* PayloadManager::GetPayload( + Payload::Id payload_id) const { + MutexLock lock(&mutex_); + return pending_payloads_.GetPayload(payload_id); +} + +Status PayloadManager::CancelPayload(ClientProxy* client, + Payload::Id payload_id) { + PendingPayload* canceled_payload = GetPayload(payload_id); + if (!canceled_payload) { + NEARBY_LOG(INFO, "PayloadManager: not found; payload_id=%" PRIX64, + payload_id); + return {Status::kPayloadUnknown}; } // Mark the payload as canceled. - canceled_payload->markLocallyCanceled(); - // TODO(tracyzhou): Add logging. + canceled_payload->MarkLocallyCanceled(); + NEARBY_LOG(INFO, "PayloadManager: canceled; id=%" PRIX64, payload_id); // Return SUCCESS immediately. Remaining cleanup and updates will be sent in - // sendPayload() or processIncomingOfflineFrame() - return Status::SUCCESS; + // SendPayload() or OnIncomingFrame() + return {Status::kSuccess}; } -template -void PayloadManager::processIncomingOfflineFrame( - ConstPtr offline_frame, const string& from_endpoint_id, - Ptr > to_client_proxy, - proto::connections::Medium current_medium) { - ScopedPtr > scoped_offline_frame(offline_frame); - const PayloadTransferFrame& payload_transfer_frame = - scoped_offline_frame->v1().payload_transfer(); +// @EndpointManagerDataPool +void PayloadManager::OnIncomingFrame( + OfflineFrame& offline_frame, const std::string& from_endpoint_id, + ClientProxy* to_client, proto::connections::Medium current_medium) { + PayloadTransferFrame& frame = + *offline_frame.mutable_v1()->mutable_payload_transfer(); - switch (payload_transfer_frame.packet_type()) { + switch (frame.packet_type()) { case PayloadTransferFrame::CONTROL: - processControlPacket(to_client_proxy, from_endpoint_id, - payload_transfer_frame); + NEARBY_LOG(INFO, + "PayloadManager::OnIncomingFrame [CONTROL]: self=%p; id=%s", + this, from_endpoint_id.c_str()); + ProcessControlPacket(to_client, from_endpoint_id, frame); break; case PayloadTransferFrame::DATA: - processDataPacket(to_client_proxy, from_endpoint_id, - payload_transfer_frame); + NEARBY_LOG(INFO, "PayloadManager::OnIncomingFrame [DATA]: self=%p; id=%s", + this, from_endpoint_id.c_str()); + ProcessDataPacket(to_client, from_endpoint_id, frame); break; default: - // TODO(tracyzhou): Add logging. + NEARBY_LOG( + INFO, + "PayloadManager: invalid frame; remote endpoint: self=%p; id=%s", + this, from_endpoint_id.c_str()); break; } + NEARBY_LOG(INFO, "PayloadManager::OnIncomingFrame [DONE]: self=%p; id=%s", + this, from_endpoint_id.c_str()); } -template -void PayloadManager::processEndpointDisconnection( - Ptr > client_proxy, const string& endpoint_id, - Ptr process_disconnection_barrier) { - payload_status_update_executor_->execute(MakePtr( - new payload_manager::ProcessEndpointDisconnectionRunnable( - self_, client_proxy, endpoint_id, - process_disconnection_barrier))); +void PayloadManager::OnEndpointDisconnect(ClientProxy* client, + const std::string& endpoint_id, + CountDownLatch* barrier) { + if (shutdown_.Get()) { + if (barrier) barrier->CountDown(); + return; + } + RunOnStatusUpdateThread([this, client, endpoint_id, barrier]() { + // Iterate through all our payloads and look for payloads associated + // with this endpoint. + MutexLock lock(&mutex_); + for (const auto& payload_id : pending_payloads_.GetAllPayloads()) { + auto* pending_payload = pending_payloads_.GetPayload(payload_id); + if (!pending_payload) continue; + auto endpoint_info = pending_payload->GetEndpoint(endpoint_id); + if (!endpoint_info) continue; + + // Stop tracking the endpoint for this payload. + pending_payload->RemoveEndpoints({endpoint_id}); + + std::int64_t payload_total_size = + pending_payload->GetInternalPayload()->GetTotalSize(); + + // If no endpoints are left for this payload, close it. + if (pending_payload->GetEndpoints().empty()) { + pending_payload->Close(); + } + + // Create the payload transfer update. + PayloadProgressInfo update{payload_id, + PayloadProgressInfo::Status::kFailure, + payload_total_size, endpoint_info->offset}; + + // Send a client notification of a payload transfer failure. + client->OnPayloadProgress(endpoint_id, update); + } + + barrier->CountDown(); + }); } -template proto::connections::PayloadStatus -PayloadManager::endpointInfoStatusToPayloadStatus( - typename EndpointInfo::Status::Value status) { +PayloadManager::EndpointInfoStatusToPayloadStatus(EndpointInfo::Status status) { switch (status) { - case EndpointInfo::Status::CANCELED: + case EndpointInfo::Status::kCanceled: return proto::connections::PayloadStatus::REMOTE_CANCELLATION; - case EndpointInfo::Status::ERROR: + case EndpointInfo::Status::kError: return proto::connections::PayloadStatus::REMOTE_ERROR; - case EndpointInfo::Status::AVAILABLE: + case EndpointInfo::Status::kAvailable: return proto::connections::PayloadStatus::SUCCESS; default: - // TODO(tracyzhou): Add logging. + NEARBY_LOG(INFO, "PayloadManager: unknown status=%d", status); return proto::connections::PayloadStatus::UNKNOWN_PAYLOAD_STATUS; } } -template proto::connections::PayloadStatus -PayloadManager::controlMessageEventToPayloadStatus( +PayloadManager::ControlMessageEventToPayloadStatus( PayloadTransferFrame::ControlMessage::EventType event) { switch (event) { case PayloadTransferFrame::ControlMessage::PAYLOAD_ERROR: @@ -729,130 +451,146 @@ PayloadManager::controlMessageEventToPayloadStatus( case PayloadTransferFrame::ControlMessage::PAYLOAD_CANCELED: return proto::connections::PayloadStatus::REMOTE_CANCELLATION; default: - // TODO(tracyzhou): Add logging. + NEARBY_LOG(INFO, "PayloadManager: unknown event=%d", event); return proto::connections::PayloadStatus::UNKNOWN_PAYLOAD_STATUS; } } -template -PayloadTransferUpdate::Status::Value -PayloadManager::payloadStatusToTransferUpdateStatus( +PayloadProgressInfo::Status PayloadManager::PayloadStatusToTransferUpdateStatus( proto::connections::PayloadStatus status) { switch (status) { case proto::connections::LOCAL_CANCELLATION: case proto::connections::REMOTE_CANCELLATION: - return PayloadTransferUpdate::Status::CANCELED; + return PayloadProgressInfo::Status::kCanceled; case proto::connections::SUCCESS: - return PayloadTransferUpdate::Status::SUCCESS; + return PayloadProgressInfo::Status::kSuccess; default: - return PayloadTransferUpdate::Status::FAILURE; + return PayloadProgressInfo::Status::kFailure; } } -template -Ptr -PayloadManager::getOutgoingPayloadExecutor( - Payload::Type::Value payload_type) { +SingleThreadExecutor* PayloadManager::GetOutgoingPayloadExecutor( + Payload::Type payload_type) { switch (payload_type) { - case Payload::Type::BYTES: - return bytes_payload_executor_.get(); - case Payload::Type::FILE: - return file_payload_executor_.get(); - case Payload::Type::STREAM: - return stream_payload_executor_.get(); + case Payload::Type::kBytes: + return &bytes_payload_executor_; + case Payload::Type::kFile: + return &file_payload_executor_; + case Payload::Type::kStream: + return &stream_payload_executor_; default: - return Ptr(); + return nullptr; } } -template -ConstPtr -PayloadManager::createPayloadHeader( - ConstPtr internal_payload) { - ScopedPtr > payload_header( - new PayloadTransferFrame::PayloadHeader()); +PayloadTransferFrame::PayloadHeader PayloadManager::CreatePayloadHeader( + const InternalPayload& internal_payload) { + PayloadTransferFrame::PayloadHeader payload_header; - payload_header->set_id(internal_payload->getId()); - payload_header->set_type(internal_payload->getType()); - payload_header->set_total_size(internal_payload->getTotalSize()); + payload_header.set_id(internal_payload.GetId()); + payload_header.set_type(internal_payload.GetType()); + payload_header.set_total_size(internal_payload.GetTotalSize()); - return ConstifyPtr(payload_header.release()); + return payload_header; } -template -ConstPtr -PayloadManager::createPayloadChunk( - std::int64_t payload_chunk_offset, ConstPtr payload_chunk_body) { - ScopedPtr > payload_chunk( - new PayloadTransferFrame::PayloadChunk()); +PayloadTransferFrame::PayloadChunk PayloadManager::CreatePayloadChunk( + std::int64_t payload_chunk_offset, ByteArray payload_chunk_body) { + PayloadTransferFrame::PayloadChunk payload_chunk; - payload_chunk->set_offset(payload_chunk_offset); - if (!payload_chunk_body.isNull()) { - payload_chunk->set_body(payload_chunk_body->getData(), - payload_chunk_body->size()); + payload_chunk.set_offset(payload_chunk_offset); + payload_chunk.set_flags(0); + if (!payload_chunk_body.Empty()) { + payload_chunk.set_body(std::string(std::move(payload_chunk_body))); + } else { + payload_chunk.set_flags(payload_chunk.flags() | + PayloadTransferFrame::PayloadChunk::LAST_CHUNK); } - // This is a null-initialized Integer, so it needs to be initialized to avoid - // inadvertent NPEs. - payload_chunk->set_flags(0); - if (payload_chunk_body.isNull()) { - payload_chunk->set_flags(payload_chunk->flags() | - PayloadTransferFrame::PayloadChunk::LAST_CHUNK); - } - - return ConstifyPtr(payload_chunk.release()); + return payload_chunk; } -template -Ptr::PendingPayload> -PayloadManager::createIncomingPayload( - const PayloadTransferFrame& payload_transfer_frame, - const string& endpoint_id) { - ScopedPtr > internal_payload( - internal_payload_factory_->createIncoming(payload_transfer_frame)); - if (internal_payload.isNull()) { - return Ptr::PendingPayload>(); +PayloadManager::PendingPayload* PayloadManager::CreateIncomingPayload( + const PayloadTransferFrame& frame, const std::string& endpoint_id) { + auto internal_payload = CreateIncomingInternalPayload(frame); + if (!internal_payload) { + return nullptr; } - std::int64_t payload_id = internal_payload->getId(); - ScopedPtr::PendingPayload> > - pending_payload(PendingPayload::createIncoming(internal_payload.release(), - endpoint_id)); - pending_payloads_->startTrackingPayload(payload_id, - pending_payload.release()); + Payload::Id payload_id = internal_payload->GetId(); + NEARBY_LOG(INFO, "CreateIncomingPayload: payload_id=%" PRIX64, payload_id); + MutexLock lock(&mutex_); + pending_payloads_.StartTrackingPayload( + payload_id, + absl::make_unique(std::move(internal_payload), + EndpointIds{endpoint_id}, true)); - return pending_payloads_->getPayload(payload_id); + return pending_payloads_.GetPayload(payload_id); } -template -void PayloadManager::sendClientCallbacksForFinishedOutgoingPayload( - Ptr > client_proxy, - const std::vector& finished_endpoint_ids, +void PayloadManager::SendClientCallbacksForFinishedOutgoingPayload( + ClientProxy* client, const EndpointIds& finished_endpoint_ids, const PayloadTransferFrame::PayloadHeader& payload_header, std::int64_t num_bytes_successfully_transferred, proto::connections::PayloadStatus status) { - payload_status_update_executor_->execute(MakePtr( - new payload_manager:: - SendClientCallbacksForFinishedOutgoingPayloadRunnable( - self_, client_proxy, finished_endpoint_ids, - payload_header, num_bytes_successfully_transferred, status))); + RunOnStatusUpdateThread([this, client, finished_endpoint_ids, payload_header, + num_bytes_successfully_transferred, status]() { + // Make sure we're still tracking this payload. + PendingPayload* pending_payload = GetPayload(payload_header.id()); + if (!pending_payload) { + return; + } + + PayloadProgressInfo update{ + payload_header.id(), + PayloadManager::PayloadStatusToTransferUpdateStatus(status), + payload_header.total_size(), num_bytes_successfully_transferred}; + for (const auto& endpoint_id : finished_endpoint_ids) { + // Skip sending notifications if we have stopped tracking this + // endpoint. + if (!pending_payload->GetEndpoint(endpoint_id)) { + continue; + } + + // Notify the client. + client->OnPayloadProgress(endpoint_id, update); + } + + // Remove these endpoints from our tracking list for this payload. + pending_payload->RemoveEndpoints(finished_endpoint_ids); + + // Close the payload if no endpoints remain. + if (pending_payload->GetEndpoints().empty()) { + pending_payload->Close(); + } + }); } -template -void PayloadManager::sendClientCallbacksForFinishedIncomingPayload( - Ptr > client_proxy, const string& endpoint_id, +void PayloadManager::SendClientCallbacksForFinishedIncomingPayload( + ClientProxy* client, const std::string& endpoint_id, const PayloadTransferFrame::PayloadHeader& payload_header, std::int64_t offset_bytes, proto::connections::PayloadStatus status) { - payload_status_update_executor_->execute(MakePtr( - new payload_manager:: - SendClientCallbacksForFinishedIncomingPayloadRunnable( - self_, client_proxy, endpoint_id, payload_header, - offset_bytes, status))); + RunOnStatusUpdateThread( + [this, client, endpoint_id, payload_header, offset_bytes, status]() { + // Make sure we're still tracking this payload. + PendingPayload* pending_payload = GetPayload(payload_header.id()); + if (!pending_payload) { + return; + } + + // Unless we never started tracking this payload (meaning we failed to + // even create the InternalPayload), notify the client (and close it). + PayloadProgressInfo update{ + payload_header.id(), + PayloadManager::PayloadStatusToTransferUpdateStatus(status), + payload_header.total_size(), offset_bytes}; + NotifyClientOfIncomingPayloadProgressInfo(client, endpoint_id, update); + DestroyPendingPayload(payload_header.id()); + }); } -template -void PayloadManager::sendControlMessage( - const std::vector& endpoint_ids, +void PayloadManager::SendControlMessage( + const EndpointIds& endpoint_ids, const PayloadTransferFrame::PayloadHeader& payload_header, std::int64_t num_bytes_successfully_transferred, PayloadTransferFrame::ControlMessage::EventType event_type) { @@ -860,29 +598,31 @@ void PayloadManager::sendControlMessage( control_message.set_event(event_type); control_message.set_offset(num_bytes_successfully_transferred); - endpoint_manager_->sendControlMessage(payload_header, control_message, + endpoint_manager_->SendControlMessage(payload_header, control_message, endpoint_ids); } -template -void PayloadManager::handleFinishedOutgoingPayload( - Ptr > client_proxy, - const std::vector& finished_endpoint_ids, +void PayloadManager::HandleFinishedOutgoingPayload( + ClientProxy* client, const EndpointIds& finished_endpoint_ids, const PayloadTransferFrame::PayloadHeader& payload_header, std::int64_t num_bytes_successfully_transferred, proto::connections::PayloadStatus status) { - sendClientCallbacksForFinishedOutgoingPayload( - client_proxy, finished_endpoint_ids, payload_header, + // This call will destroy a pending payload. + SendClientCallbacksForFinishedOutgoingPayload( + client, finished_endpoint_ids, payload_header, num_bytes_successfully_transferred, status); switch (status) { case proto::connections::PayloadStatus::LOCAL_ERROR: - sendControlMessage(finished_endpoint_ids, payload_header, + SendControlMessage(finished_endpoint_ids, payload_header, num_bytes_successfully_transferred, PayloadTransferFrame::ControlMessage::PAYLOAD_ERROR); break; case proto::connections::PayloadStatus::LOCAL_CANCELLATION: - sendControlMessage( + NEARBY_LOG(INFO, + "Sending PAYLOAD_CANCEL to receiver side; payload_id=%" PRIX64, + static_cast(payload_header.id())); + SendControlMessage( finished_endpoint_ids, payload_header, num_bytes_successfully_transferred, PayloadTransferFrame::ControlMessage::PAYLOAD_CANCELED); @@ -890,10 +630,8 @@ void PayloadManager::handleFinishedOutgoingPayload( case proto::connections::PayloadStatus::ENDPOINT_IO_ERROR: // Unregister these endpoints, since we had an IO error on the physical // connection. - for (std::vector::const_iterator it = - finished_endpoint_ids.begin(); - it != finished_endpoint_ids.end(); it++) { - endpoint_manager_->discardEndpoint(client_proxy, *it); + for (const auto& endpoint_id : finished_endpoint_ids) { + endpoint_manager_->DiscardEndpoint(client, endpoint_id); } break; case proto::connections::PayloadStatus::REMOTE_ERROR: @@ -901,28 +639,26 @@ void PayloadManager::handleFinishedOutgoingPayload( // No special handling needed for these. break; default: - // TODO(tracyzhou): Add logging. + NEARBY_LOG(INFO, "PayloadManager: unknown status=%d", status); break; } } -template -void PayloadManager::handleFinishedIncomingPayload( - Ptr > client_proxy, const string& endpoint_id, +void PayloadManager::HandleFinishedIncomingPayload( + ClientProxy* client, const std::string& endpoint_id, const PayloadTransferFrame::PayloadHeader& payload_header, std::int64_t offset_bytes, proto::connections::PayloadStatus status) { - sendClientCallbacksForFinishedIncomingPayload( - client_proxy, endpoint_id, payload_header, offset_bytes, status); + SendClientCallbacksForFinishedIncomingPayload( + client, endpoint_id, payload_header, offset_bytes, status); switch (status) { case proto::connections::PayloadStatus::LOCAL_ERROR: - sendControlMessage(std::vector(1, endpoint_id), payload_header, - offset_bytes, + SendControlMessage({endpoint_id}, payload_header, offset_bytes, PayloadTransferFrame::ControlMessage::PAYLOAD_ERROR); break; case proto::connections::PayloadStatus::LOCAL_CANCELLATION: - sendControlMessage( - std::vector(1, endpoint_id), payload_header, offset_bytes, + SendControlMessage( + {endpoint_id}, payload_header, offset_bytes, PayloadTransferFrame::ControlMessage::PAYLOAD_CANCELED); break; default: @@ -931,73 +667,144 @@ void PayloadManager::handleFinishedIncomingPayload( } } -template -void PayloadManager::handleSuccessfulOutgoingChunk( - Ptr > client_proxy, const string& endpoint_id, +void PayloadManager::HandleSuccessfulOutgoingChunk( + ClientProxy* client, const std::string& endpoint_id, const PayloadTransferFrame::PayloadHeader& payload_header, std::int32_t payload_chunk_flags, std::int64_t payload_chunk_offset, std::int64_t payload_chunk_body_size) { - payload_status_update_executor_->execute(MakePtr( - new payload_manager::HandleSuccessfulOutgoingChunkRunnable( - self_, client_proxy, endpoint_id, payload_header, - payload_chunk_flags, payload_chunk_offset, payload_chunk_body_size))); + RunOnStatusUpdateThread([this, client, endpoint_id, payload_header, + payload_chunk_flags, payload_chunk_offset, + payload_chunk_body_size]() { + // Make sure we're still tracking this payload and its associated + // endpoint. + PendingPayload* pending_payload = GetPayload(payload_header.id()); + if (!pending_payload || !pending_payload->GetEndpoint(endpoint_id)) { + NEARBY_LOG(INFO, + "HandleSuccessfulOutgoingChunk: endpoint not found: id=%s", + endpoint_id.c_str()); + return; + } + + bool is_last_chunk = (payload_chunk_flags & + PayloadTransferFrame::PayloadChunk::LAST_CHUNK) != 0; + PayloadProgressInfo update{ + payload_header.id(), + is_last_chunk ? PayloadProgressInfo::Status::kSuccess + : PayloadProgressInfo::Status::kInProgress, + payload_header.total_size(), + is_last_chunk ? payload_chunk_offset + : payload_chunk_offset + payload_chunk_body_size}; + + // Notify the client. + client->OnPayloadProgress(endpoint_id, update); + + if (is_last_chunk) { + // Stop tracking this endpoint. + pending_payload->RemoveEndpoints({endpoint_id}); + + // Close the payload if no endpoints remain. + if (pending_payload->GetEndpoints().empty()) { + pending_payload->Close(); + } + } + }); } -template -void PayloadManager::handleSuccessfulIncomingChunk( - Ptr > client_proxy, const string& endpoint_id, +// @PayloadManagerStatusUpdateThread +void PayloadManager::DestroyPendingPayload(Payload::Id payload_id) { + bool is_incoming = false; + { + MutexLock lock(&mutex_); + auto pending = pending_payloads_.StopTrackingPayload(payload_id); + if (!pending) return; + is_incoming = pending->IsIncoming(); + const char* direction = is_incoming ? "incoming" : "outgoing"; + NEARBY_LOG(INFO, + "PayloadManager: destroying %s pending payload: " + "self=%p; id=%" PRIX64, + direction, this, payload_id); + pending->Close(); + pending.reset(); + } + if (!is_incoming) NotifyShutdown(); +} + +void PayloadManager::HandleSuccessfulIncomingChunk( + ClientProxy* client, const std::string& endpoint_id, const PayloadTransferFrame::PayloadHeader& payload_header, std::int32_t payload_chunk_flags, std::int64_t payload_chunk_offset, std::int64_t payload_chunk_body_size) { - payload_status_update_executor_->execute(MakePtr( - new payload_manager::HandleSuccessfulIncomingChunkRunnable( - self_, client_proxy, endpoint_id, payload_header, - payload_chunk_flags, payload_chunk_offset, payload_chunk_body_size))); + RunOnStatusUpdateThread([this, client, endpoint_id, payload_header, + payload_chunk_flags, payload_chunk_offset, + payload_chunk_body_size]() { + // Make sure we're still tracking this payload. + PendingPayload* pending_payload = GetPayload(payload_header.id()); + if (!pending_payload) { + return; + } + + bool is_last_chunk = (payload_chunk_flags & + PayloadTransferFrame::PayloadChunk::LAST_CHUNK) != 0; + PayloadProgressInfo update{ + payload_header.id(), + is_last_chunk ? PayloadProgressInfo::Status::kSuccess + : PayloadProgressInfo::Status::kInProgress, + payload_header.total_size(), + is_last_chunk ? payload_chunk_offset + : payload_chunk_offset + payload_chunk_body_size}; + + // Notify the client of this update. + NotifyClientOfIncomingPayloadProgressInfo(client, endpoint_id, update); + }); } -template -void PayloadManager::processDataPacket( - Ptr > to_client_proxy, const string& from_endpoint_id, - const PayloadTransferFrame& payload_transfer_frame) { - const PayloadTransferFrame::PayloadHeader& payload_header = - payload_transfer_frame.payload_header(); - const PayloadTransferFrame::PayloadChunk& payload_chunk = - payload_transfer_frame.payload_chunk(); - // TODO(tracyzhou): Add logging. +// @EndpointManagerDataPool +void PayloadManager::ProcessDataPacket( + ClientProxy* to_client, const std::string& from_endpoint_id, + PayloadTransferFrame& payload_transfer_frame) { + PayloadTransferFrame::PayloadHeader& payload_header = + *payload_transfer_frame.mutable_payload_header(); + PayloadTransferFrame::PayloadChunk& payload_chunk = + *payload_transfer_frame.mutable_payload_chunk(); - Ptr::PendingPayload> pending_payload; + PendingPayload* pending_payload; if (payload_chunk.offset() == 0) { pending_payload = - createIncomingPayload(payload_transfer_frame, from_endpoint_id); - if (pending_payload.isNull()) { - // TODO(tracyzhou): Add logging. + CreateIncomingPayload(payload_transfer_frame, from_endpoint_id); + if (!pending_payload) { // Send the error to the remote endpoint. - sendControlMessage(std::vector(1, from_endpoint_id), - payload_header, payload_chunk.offset(), + SendControlMessage({from_endpoint_id}, payload_header, + payload_chunk.offset(), PayloadTransferFrame::ControlMessage::PAYLOAD_ERROR); return; } // Also, let the client know of this new incoming payload. - payload_status_update_executor_->execute( - MakePtr(new payload_manager::ProcessDataPacketRunnable( - to_client_proxy, from_endpoint_id, - pending_payload->getInternalPayload()->releasePayload()))); - // TODO(tracyzhou): Add logging. + RunOnStatusUpdateThread([to_client, from_endpoint_id, pending_payload]() { + NEARBY_LOG(INFO, "ProcessDataPacket [new]: id=%s; payload_id=%" PRIX64, + from_endpoint_id.c_str(), pending_payload->GetId()); + to_client->OnPayload( + from_endpoint_id, + pending_payload->GetInternalPayload()->ReleasePayload()); + }); } else { - pending_payload = pending_payloads_->getPayload(payload_header.id()); - if (pending_payload.isNull()) { - // TODO(tracyzhou): Add logging. + pending_payload = GetPayload(payload_header.id()); + if (!pending_payload) { + NEARBY_LOG(INFO, + "ProcessDataPacket: [missing] id=%s; payload_id=%" PRIX64, + from_endpoint_id.c_str(), + static_cast(payload_header.id())); return; } } - if (pending_payload->isLocallyCanceled()) { + if (pending_payload->IsLocallyCanceled()) { // This incoming payload was canceled by the client. Drop this frame and do // all the cleanup. See go/nc-cancel-payload - handleFinishedIncomingPayload( - to_client_proxy, from_endpoint_id, payload_header, - payload_chunk.offset(), + NEARBY_LOG(INFO, "ProcessDataPacket: [cancel] id=%s; payload_id=%" PRIX64, + from_endpoint_id.c_str(), pending_payload->GetId()); + HandleFinishedIncomingPayload( + to_client, from_endpoint_id, payload_header, payload_chunk.offset(), proto::connections::PayloadStatus::LOCAL_CANCELLATION); return; } @@ -1007,69 +814,73 @@ void PayloadManager::processDataPacket( // back to the client. For the sake of accuracy, we update the pending payload // here because it's after all payload terminating events are handled, but // right before we actually start attaching the next chunk. - pending_payload->setOffsetForEndpoint(from_endpoint_id, + pending_payload->SetOffsetForEndpoint(from_endpoint_id, payload_chunk.offset()); - Exception::Value attach_next_chunk_exception = - pending_payload->getInternalPayload()->attachNextChunk( - MakeConstPtr(new ByteArray(payload_chunk.body().data(), - payload_chunk.body().size()))); - if (Exception::NONE != attach_next_chunk_exception) { - if (Exception::IO == attach_next_chunk_exception) { - // TODO(tracyzhou): Add logging. - handleFinishedIncomingPayload( - to_client_proxy, from_endpoint_id, payload_header, - payload_chunk.offset(), - proto::connections::PayloadStatus::LOCAL_ERROR); - return; - } + // Save size of packet before we move it. + std::int64_t payload_body_size = payload_chunk.body().size(); + if (pending_payload->GetInternalPayload() + ->AttachNextChunk(ByteArray(std::move(*payload_chunk.mutable_body()))) + .Raised()) { + NEARBY_LOG(INFO, + "ProcessDataPacket: [data: error] id=%s; payload_id=%" PRIX64, + from_endpoint_id.c_str(), pending_payload->GetId()); + HandleFinishedIncomingPayload( + to_client, from_endpoint_id, payload_header, payload_chunk.offset(), + proto::connections::PayloadStatus::LOCAL_ERROR); + return; } - handleSuccessfulIncomingChunk( - to_client_proxy, from_endpoint_id, payload_header, payload_chunk.flags(), - payload_chunk.offset(), payload_chunk.body().size()); + NEARBY_LOG(INFO, "ProcessDataPacket: [data: ok] id=%s; payload_id=%" PRIX64, + from_endpoint_id.c_str(), pending_payload->GetId()); + HandleSuccessfulIncomingChunk(to_client, from_endpoint_id, payload_header, + payload_chunk.flags(), payload_chunk.offset(), + payload_body_size); } -template -void PayloadManager::processControlPacket( - Ptr > to_client_proxy, const string& from_endpoint_id, - const PayloadTransferFrame& payload_transfer_frame) { +// @EndpointManagerDataPool +void PayloadManager::ProcessControlPacket( + ClientProxy* to_client, const std::string& from_endpoint_id, + PayloadTransferFrame& payload_transfer_frame) { const PayloadTransferFrame::PayloadHeader& payload_header = payload_transfer_frame.payload_header(); const PayloadTransferFrame::ControlMessage& control_message = payload_transfer_frame.control_message(); - Ptr::PendingPayload> pending_payload = - pending_payloads_->getPayload(payload_header.id()); - if (pending_payload.isNull()) { + PendingPayload* pending_payload = GetPayload(payload_header.id()); + if (!pending_payload) { // TODO(tracyzhou): Add logging. return; } switch (control_message.event()) { case PayloadTransferFrame::ControlMessage::PAYLOAD_CANCELED: - if (pending_payload->isIncoming()) { + if (pending_payload->IsIncoming()) { + NEARBY_LOG(INFO, "Incoming PAYLOAD_CANCELED: from id=%s; self=%p", + from_endpoint_id.c_str(), this); // No need to mark the pending payload as cancelled, since this is a // remote cancellation for an incoming payload -- we handle everything // inline here. - handleFinishedIncomingPayload( - to_client_proxy, from_endpoint_id, payload_header, + HandleFinishedIncomingPayload( + to_client, from_endpoint_id, payload_header, control_message.offset(), - controlMessageEventToPayloadStatus(control_message.event())); + ControlMessageEventToPayloadStatus(control_message.event())); } else { + NEARBY_LOG(INFO, "Outgoing PAYLOAD_CANCELED: from id=%s; self=%p", + from_endpoint_id.c_str(), this); // Mark the payload as canceled *for this endpoint*. - pending_payload->setEndpointStatusFromControlMessage(from_endpoint_id, + pending_payload->SetEndpointStatusFromControlMessage(from_endpoint_id, control_message); } // TODO(tracyzhou): Add logging. break; case PayloadTransferFrame::ControlMessage::PAYLOAD_ERROR: - if (pending_payload->isIncoming()) { - handleFinishedIncomingPayload( - to_client_proxy, from_endpoint_id, payload_header, + if (pending_payload->IsIncoming()) { + HandleFinishedIncomingPayload( + to_client, from_endpoint_id, payload_header, control_message.offset(), - controlMessageEventToPayloadStatus(control_message.event())); + ControlMessageEventToPayloadStatus(control_message.event())); } else { - pending_payload->setEndpointStatusFromControlMessage(from_endpoint_id, + pending_payload->SetEndpointStatusFromControlMessage(from_endpoint_id, control_message); } break; @@ -1079,277 +890,177 @@ void PayloadManager::processControlPacket( } } -template -void PayloadManager::notifyClientOfIncomingPayloadTransferUpdate( - Ptr > client_proxy, const string& endpoint_id, - const PayloadTransferUpdate& payload_transfer_update, - bool done_with_payload) { - client_proxy->onPayloadTransferUpdate(endpoint_id, payload_transfer_update); - if (done_with_payload) { - // We're done with this payload (either received the last chunk, or had a - // failure), so remove it from the incoming payloads that we're tracking. - Ptr::PendingPayload> pending_payload = - pending_payloads_->stopTrackingPayload( - payload_transfer_update.payload_id); - pending_payload->close(); - pending_payload.destroy(); - } -} - -template -void PayloadManager::enqueueOutgoingPayload( - Ptr executor, - Ptr runnable) { - executor->execute(runnable); +// @PayloadManagerStatusUpdateThread +void PayloadManager::NotifyClientOfIncomingPayloadProgressInfo( + ClientProxy* client, const std::string& endpoint_id, + const PayloadProgressInfo& payload_transfer_update) { + client->OnPayloadProgress(endpoint_id, payload_transfer_update); } ///////////////////////////////// EndpointInfo ///////////////////////////////// -template -PayloadManager::EndpointInfo::EndpointInfo(string id) - : id_(id), status_(Status::AVAILABLE), offset_(0) {} - -template -typename PayloadManager::EndpointInfo::Status::Value -PayloadManager::EndpointInfo::controlMessageEventToEndpointInfoStatus( +PayloadManager::EndpointInfo::Status +PayloadManager::EndpointInfo::ControlMessageEventToEndpointInfoStatus( PayloadTransferFrame::ControlMessage::EventType event) { switch (event) { case PayloadTransferFrame::ControlMessage::PAYLOAD_ERROR: - return Status::ERROR; + return Status::kError; case PayloadTransferFrame::ControlMessage::PAYLOAD_CANCELED: - return Status::CANCELED; + return Status::kCanceled; default: // TODO(tracyzhou): Add logging. - return Status::UNKNOWN; + return Status::kUnknown; } } -template -string PayloadManager::EndpointInfo::getId() const { - return id_; -} - -template -typename PayloadManager::EndpointInfo::Status::Value -PayloadManager::EndpointInfo::getStatus() const { - return status_; -} - -template -std::int64_t PayloadManager::EndpointInfo::getOffset() const { - return offset_; -} - -template -void PayloadManager::EndpointInfo::setStatus( +void PayloadManager::EndpointInfo::SetStatusFromControlMessage( const PayloadTransferFrame::ControlMessage& control_message) { - status_ = controlMessageEventToEndpointInfoStatus(control_message.event()); -} - -template -void PayloadManager::EndpointInfo::setOffset(std::int64_t offset) { - offset_ = offset; + status.Set(ControlMessageEventToEndpointInfoStatus(control_message.event())); } //////////////////////////////// PendingPayload //////////////////////////////// -template -Ptr::PendingPayload> -PayloadManager::PendingPayload::createIncoming( - Ptr internal_payload, const string& endpoint_id) { - return MakeRefCountedPtr(new PendingPayload( - internal_payload, std::vector(1, endpoint_id), true)); -} - -template -Ptr::PendingPayload> -PayloadManager::PendingPayload::createOutgoing( - Ptr internal_payload, - const std::vector& endpoint_ids) { - return MakeRefCountedPtr( - new PendingPayload(internal_payload, endpoint_ids, false)); -} - -template -PayloadManager::PendingPayload::PendingPayload( - Ptr internal_payload, - const std::vector& endpoint_ids, bool is_incoming) - : lock_(Platform::createLock()), - internal_payload_(internal_payload), - is_incoming_(is_incoming), - is_locally_cancelled_(Platform::createAtomicBoolean(false)), - endpoints_() { - for (std::vector::const_iterator it = endpoint_ids.begin(); - it != endpoint_ids.end(); it++) { - endpoints_.insert(std::make_pair(*it, MakePtr(new EndpointInfo(*it)))); +PayloadManager::PendingPayload::PendingPayload( + std::unique_ptr internal_payload, + const EndpointIds& endpoint_ids, bool is_incoming) + : is_incoming_(is_incoming), + internal_payload_(std::move(internal_payload)) { + // Initially we mark all endpoints as available. + // Later on some may become canceled, some may experience data transfer + // failures. Any of these situations will cause endpoint to be marked as + // unavailable. + for (const auto& id : endpoint_ids) { + endpoints_.emplace(id, EndpointInfo{ + .id = id, + .status {EndpointInfo::Status::kAvailable}, + }); } } -template -PayloadManager::PendingPayload::~PendingPayload() { - for (typename EndpointsMap::iterator it = endpoints_.begin(); - it != endpoints_.end(); it++) { - it->second.destroy(); - } - endpoints_.clear(); +Payload::Id PayloadManager::PendingPayload::GetId() const { + return internal_payload_->GetId(); } -template -std::int64_t PayloadManager::PendingPayload::getId() { - return internal_payload_->getId(); -} - -template -Ptr -PayloadManager::PendingPayload::getInternalPayload() { +InternalPayload* PayloadManager::PendingPayload::GetInternalPayload() { return internal_payload_.get(); } -template -bool PayloadManager::PendingPayload::isLocallyCanceled() { - return is_locally_cancelled_->get(); +bool PayloadManager::PendingPayload::IsLocallyCanceled() const { + return is_locally_canceled_.Get(); } -template -void PayloadManager::PendingPayload::markLocallyCanceled() { - is_locally_cancelled_->set(true); +void PayloadManager::PendingPayload::MarkLocallyCanceled() { + is_locally_canceled_.Set(true); } -template -bool PayloadManager::PendingPayload::isIncoming() { - return is_incoming_; -} +bool PayloadManager::PendingPayload::IsIncoming() const { return is_incoming_; } -template -std::vector::EndpointInfo> > -PayloadManager::PendingPayload::getEndpoints() const { - Synchronized s(lock_.get()); +std::vector +PayloadManager::PendingPayload::GetEndpoints() const { + MutexLock lock(&mutex_); - std::vector::EndpointInfo> > result; - for (typename EndpointsMap::const_iterator it = endpoints_.begin(); - it != endpoints_.end(); it++) { - result.push_back(it->second); + std::vector result; + for (const auto& item : endpoints_) { + result.push_back(&item.second); } return result; } -template -Ptr::EndpointInfo> -PayloadManager::PendingPayload::getEndpoint( - const string& endpoint_id) { - Synchronized s(lock_.get()); +PayloadManager::EndpointInfo* PayloadManager::PendingPayload::GetEndpoint( + const std::string& endpoint_id) { + MutexLock lock(&mutex_); - typename EndpointsMap::iterator it = endpoints_.find(endpoint_id); + auto it = endpoints_.find(endpoint_id); if (it == endpoints_.end()) { - return Ptr::EndpointInfo>(); + return {}; } - return it->second; + return &it->second; } -template -void PayloadManager::PendingPayload::removeEndpoints( - const std::vector& endpoint_ids_to_remove) { - Synchronized s(lock_.get()); +void PayloadManager::PendingPayload::RemoveEndpoints( + const EndpointIds& endpoint_ids) { + MutexLock lock(&mutex_); - for (std::vector::const_iterator it = endpoint_ids_to_remove.begin(); - it != endpoint_ids_to_remove.end(); it++) { - payload_manager::eraseOwnedPtrFromMap(endpoints_, *it); + for (const auto& id : endpoint_ids) { + endpoints_.erase(id); } } -template -void PayloadManager::PendingPayload:: - setEndpointStatusFromControlMessage( - const string& endpoint_id, - const PayloadTransferFrame::ControlMessage& control_message) { - Synchronized s(lock_.get()); +void PayloadManager::PendingPayload::SetEndpointStatusFromControlMessage( + const std::string& endpoint_id, + const PayloadTransferFrame::ControlMessage& control_message) { + MutexLock lock(&mutex_); - typename EndpointsMap::iterator it = endpoints_.find(endpoint_id); - if (it != endpoints_.end()) { - it->second->setStatus(control_message); + auto item = endpoints_.find(endpoint_id); + if (item != endpoints_.end()) { + item->second.SetStatusFromControlMessage(control_message); } } -template -void PayloadManager::PendingPayload::setOffsetForEndpoint( - const string& endpoint_id, std::int64_t offset) { - Synchronized s(lock_.get()); +void PayloadManager::PendingPayload::SetOffsetForEndpoint( + const std::string& endpoint_id, std::int64_t offset) { + MutexLock lock(&mutex_); - typename EndpointsMap::iterator it = endpoints_.find(endpoint_id); - if (it != endpoints_.end()) { - it->second->setOffset(offset); + auto item = endpoints_.find(endpoint_id); + if (item != endpoints_.end()) { + item->second.offset = offset; } } -template -void PayloadManager::PendingPayload::close() { - internal_payload_->close(); +void PayloadManager::PendingPayload::Close() { + if (internal_payload_) internal_payload_->Close(); + close_event_.CountDown(); +} + +bool PayloadManager::PendingPayload::WaitForClose() { + return close_event_.Await(kWaitCloseTimeout).result(); +} + +bool PayloadManager::PendingPayload::IsClosed() { + return close_event_.Await(absl::ZeroDuration()).result(); +} + +void PayloadManager::RunOnStatusUpdateThread(std::function runnable) { + payload_status_update_executor_.Execute(std::move(runnable)); } /////////////////////////////// PendingPayloads /////////////////////////////// -template -PayloadManager::PendingPayloads::PendingPayloads() - : lock_(Platform::createLock()), pending_payloads_() {} +void PayloadManager::PendingPayloads::StartTrackingPayload( + Payload::Id payload_id, std::unique_ptr pending_payload) { + MutexLock lock(&mutex_); -template -PayloadManager::PendingPayloads::~PendingPayloads() { - for (typename PendingPayloadsMap::iterator it = pending_payloads_.begin(); - it != pending_payloads_.end(); it++) { - it->second.destroy(); - } - pending_payloads_.clear(); + auto pair = pending_payloads_.emplace(payload_id, std::move(pending_payload)); + NEARBY_LOG(INFO, "StartTrackingPayload: payload_id=%" PRIX64 "; inserted=%d", + payload_id, pair.second); } -template -void PayloadManager::PendingPayloads::startTrackingPayload( - std::int64_t payload_id, - Ptr::PendingPayload> pending_payload) { - Synchronized s(lock_.get()); +std::unique_ptr +PayloadManager::PendingPayloads::StopTrackingPayload(Payload::Id payload_id) { + MutexLock lock(&mutex_); - pending_payloads_.insert(std::make_pair(payload_id, pending_payload)); + auto it = pending_payloads_.find(payload_id); + if (it == pending_payloads_.end()) return {}; + + auto item = pending_payloads_.extract(it); + return std::move(item.mapped()); } -template -Ptr::PendingPayload> -PayloadManager::PendingPayloads::stopTrackingPayload( - std::int64_t payload_id) { - Synchronized s(lock_.get()); +PayloadManager::PendingPayload* PayloadManager::PendingPayloads::GetPayload( + Payload::Id payload_id) const { + MutexLock lock(&mutex_); - typename PendingPayloadsMap::iterator it = pending_payloads_.find(payload_id); - if (it == pending_payloads_.end()) { - return Ptr::PendingPayload>(); - } - - Ptr::PendingPayload> pending_payload = - it->second; - pending_payloads_.erase(it); - - return pending_payload; + auto item = pending_payloads_.find(payload_id); + return item != pending_payloads_.end() ? item->second.get() : nullptr; } -template -Ptr::PendingPayload> -PayloadManager::PendingPayloads::getPayload(std::int64_t payload_id) { - Synchronized s(lock_.get()); +std::vector PayloadManager::PendingPayloads::GetAllPayloads() { + MutexLock lock(&mutex_); - typename PendingPayloadsMap::iterator it = pending_payloads_.find(payload_id); - if (it == pending_payloads_.end()) { - return Ptr::PendingPayload>(); - } - return it->second; -} - -template -std::vector::PendingPayload> > -PayloadManager::PendingPayloads::getAllPayloads() { - Synchronized s(lock_.get()); - - std::vector::PendingPayload> > result; - for (typename PendingPayloadsMap::iterator it = pending_payloads_.begin(); - it != pending_payloads_.end(); it++) { - result.push_back(it->second); + std::vector result; + for (const auto& item : pending_payloads_) { + result.push_back(item.first); } return result; } diff --git a/cpp/core/internal/payload_manager.h b/cpp/core/internal/payload_manager.h index 4058ec6f..d7033c60 100644 --- a/cpp/core/internal/payload_manager.h +++ b/cpp/core/internal/payload_manager.h @@ -2,288 +2,284 @@ #define CORE_INTERNAL_PAYLOAD_MANAGER_H_ #include -#include +#include +#include #include #include "core/internal/client_proxy.h" #include "core/internal/endpoint_manager.h" #include "core/internal/internal_payload.h" -#include "core/internal/internal_payload_factory.h" -#include "core/internal/loop_runner.h" #include "core/listeners.h" #include "core/payload.h" #include "core/status.h" #include "proto/connections/offline_wire_formats.pb.h" -#include "platform/api/count_down_latch.h" -#include "platform/api/lock.h" -#include "platform/byte_array.h" -#include "platform/port/string.h" -#include "platform/ptr.h" -#include "platform/runnable.h" +#include "platform/base/byte_array.h" +#include "platform/public/atomic_boolean.h" +#include "platform/public/atomic_reference.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/mutex.h" #include "proto/connections_enums.pb.h" +#include "absl/container/flat_hash_map.h" namespace location { namespace nearby { namespace connections { -namespace payload_manager { - -template -class SendPayloadRunnable; -template -class ProcessEndpointDisconnectionRunnable; -template -class SendClientCallbacksForFinishedOutgoingPayloadRunnable; -template -class SendClientCallbacksForFinishedIncomingPayloadRunnable; -template -class HandleSuccessfulOutgoingChunkRunnable; -template -class HandleSuccessfulIncomingChunkRunnable; - -} // namespace payload_manager - -template -class PayloadManager - : public EndpointManager::IncomingOfflineFrameProcessor { +class PayloadManager : public EndpointManager::FrameProcessor { public: - explicit PayloadManager(Ptr > endpoint_manager); + using EndpointIds = std::vector; + constexpr static const absl::Duration kWaitCloseTimeout = + absl::Milliseconds(5000); + + explicit PayloadManager(EndpointManager& endpoint_manager); ~PayloadManager() override; - void sendPayload(Ptr > client_proxy, - const std::vector& endpoint_ids, - ConstPtr payload); - Status::Value cancelPayload(Ptr > client_proxy, - std::int64_t payload_id); + void SendPayload(ClientProxy* client, const EndpointIds& endpoint_ids, + Payload payload); + Status CancelPayload(ClientProxy* client, Payload::Id payload_id); // @EndpointManagerReaderThread - void processIncomingOfflineFrame( - ConstPtr offline_frame, const string& from_endpoint_id, - Ptr > to_client_proxy, - proto::connections::Medium current_medium) override; + void OnIncomingFrame(OfflineFrame& offline_frame, + const std::string& from_endpoint_id, + ClientProxy* to_client, + proto::connections::Medium current_medium) override; // @EndpointManagerThread - void processEndpointDisconnection( - Ptr > client_proxy, const string& endpoint_id, - Ptr process_disconnection_barrier) override; + void OnEndpointDisconnect(ClientProxy* client, const std::string& endpoint_id, + CountDownLatch* barrier) override; + + void DisconnectFromEndpointManager(); private: // Information about an endpoint for a particular payload. - class EndpointInfo { - public: + struct EndpointInfo { // Status set for the endpoint out-of-band via a ControlMessage. - struct Status { - enum Value { UNKNOWN, AVAILABLE, CANCELED, ERROR }; + enum class Status { + kUnknown, + kAvailable, + kCanceled, + kError, }; - explicit EndpointInfo(string id); + void SetStatusFromControlMessage( + const PayloadTransferFrame::ControlMessage& control_message); - string getId() const; - typename EndpointInfo::Status::Value getStatus() const; - std::int64_t getOffset() const; - - void setStatus(const PayloadTransferFrame::ControlMessage& control_message); - void setOffset(std::int64_t offset); - - private: - static typename Status::Value controlMessageEventToEndpointInfoStatus( + static Status ControlMessageEventToEndpointInfoStatus( PayloadTransferFrame::ControlMessage::EventType event); - const string id_; - typename Status::Value status_; - std::int64_t offset_; + std::string id; + AtomicReference status {Status::kUnknown}; + std::int64_t offset = 0; }; // Tracks state for an InternalPayload and the endpoints associated with it. class PendingPayload { public: - static Ptr createIncoming( - Ptr internal_payload, const string& endpoint_id); - static Ptr createOutgoing( - Ptr internal_payload, - const std::vector& endpoint_ids); + PendingPayload(std::unique_ptr internal_payload, + const EndpointIds& endpoint_ids, bool is_incoming); + PendingPayload(PendingPayload&&) = default; + PendingPayload& operator=(PendingPayload&&) = default; - ~PendingPayload(); + ~PendingPayload() { Close(); } - std::int64_t getId(); + Payload::Id GetId() const; - Ptr getInternalPayload(); + InternalPayload* GetInternalPayload(); - bool isLocallyCanceled(); - void markLocallyCanceled(); - bool isIncoming(); + bool IsLocallyCanceled() const; + void MarkLocallyCanceled(); + bool IsIncoming() const; // Gets the EndpointInfo objects for the endpoints (still) associated with // this payload. - std::vector > getEndpoints() const; + std::vector GetEndpoints() const + ABSL_LOCKS_EXCLUDED(mutex_); // Returns the EndpointInfo for a given endpoint ID. Returns null if the // endpoint is not associated with this payload. - Ptr getEndpoint(const string& endpoint_id); + EndpointInfo* GetEndpoint(const std::string& endpoint_id) + ABSL_LOCKS_EXCLUDED(mutex_); // Removes the given endpoints, e.g. on error. - void removeEndpoints(const std::vector& endpoint_ids_to_remove); + void RemoveEndpoints(const EndpointIds& endpoint_ids_to_remove) + ABSL_LOCKS_EXCLUDED(mutex_); // Sets the status for a particular endpoint. - void setEndpointStatusFromControlMessage( - const string& endpoint_id, - const PayloadTransferFrame::ControlMessage& control_message); + void SetEndpointStatusFromControlMessage( + const std::string& endpoint_id, + const PayloadTransferFrame::ControlMessage& control_message) + ABSL_LOCKS_EXCLUDED(mutex_); // Sets the offset for a particular endpoint. - void setOffsetForEndpoint(const string& endpoint_id, std::int64_t offset); + void SetOffsetForEndpoint(const std::string& endpoint_id, + std::int64_t offset) ABSL_LOCKS_EXCLUDED(mutex_); - void close(); + // Closes internal_payload_ and triggers close_event_. + // Close is called when a pending peyload does not have associated + // endpoints. + void Close(); + + // Waits for close_event_ or for timeout to happen. + // Returns true, if event happened, false otherwise. + bool WaitForClose(); + bool IsClosed(); private: - PendingPayload(Ptr internal_payload, - const std::vector& endpoint_ids, bool is_incoming); - - ScopedPtr > lock_; - - ScopedPtr > internal_payload_; - const bool is_incoming_; - ScopedPtr > is_locally_cancelled_; - typedef std::map > EndpointsMap; - EndpointsMap endpoints_; + mutable Mutex mutex_; + bool is_incoming_; + AtomicBoolean is_locally_canceled_{false}; + CountDownLatch close_event_{1}; + std::unique_ptr internal_payload_; + absl::flat_hash_map endpoints_ + ABSL_GUARDED_BY(mutex_); }; // Tracks and manages PendingPayload objects in a synchronized manner. class PendingPayloads { public: - PendingPayloads(); - ~PendingPayloads(); + PendingPayloads() = default; + ~PendingPayloads() = default; - void startTrackingPayload(std::int64_t payload_id, - Ptr pending_payload); - Ptr stopTrackingPayload(std::int64_t payload_id); - Ptr getPayload(std::int64_t payload_id); - std::vector > getAllPayloads(); + void StartTrackingPayload(Payload::Id payload_id, + std::unique_ptr pending_payload) + ABSL_LOCKS_EXCLUDED(mutex_); + std::unique_ptr StopTrackingPayload(Payload::Id payload_id) + ABSL_LOCKS_EXCLUDED(mutex_); + PendingPayload* GetPayload(Payload::Id payload_id) const + ABSL_LOCKS_EXCLUDED(mutex_); + std::vector GetAllPayloads() ABSL_LOCKS_EXCLUDED(mutex_); private: - ScopedPtr > lock_; - typedef std::map > PendingPayloadsMap; - PendingPayloadsMap pending_payloads_; + mutable Mutex mutex_; + absl::flat_hash_map> + pending_payloads_ ABSL_GUARDED_BY(mutex_); }; - template - friend class payload_manager::SendPayloadRunnable; - template - friend class payload_manager::ProcessEndpointDisconnectionRunnable; - template - friend class payload_manager:: - SendClientCallbacksForFinishedOutgoingPayloadRunnable; - template - friend class payload_manager:: - SendClientCallbacksForFinishedIncomingPayloadRunnable; - template - friend class payload_manager::HandleSuccessfulOutgoingChunkRunnable; - template - friend class payload_manager::HandleSuccessfulIncomingChunkRunnable; + using Endpoints = std::vector; + static std::string ToString(const EndpointIds& endpoint_ids); + static std::string ToString(const Endpoints& endpoints); + + // Splits the endpoints for this payload by availability. + // Returns a pair of lists of EndpointInfo*, with the first being the list of + // still-available endpoints, and the second for unavailable endpoints. + static std::pair GetAvailableAndUnavailableEndpoints( + const PendingPayload& pending_payload); + + // Converts list of EndpointInfo to list of Endpoint ids. + // Returns list of endpoint ids. + static EndpointIds EndpointsToEndpointIds(const Endpoints& endpoints); + + bool SendPayloadLoop(ClientProxy* client, PendingPayload& pending_payload, + PayloadTransferFrame::PayloadHeader& payload_header, + std::int64_t& next_chunk_offset); + void SendClientCallbacksForFinishedIncomingPayloadRunnable( + ClientProxy* client, const std::string& endpoint_id, + const PayloadTransferFrame::PayloadHeader& payload_header, + std::int64_t offset_bytes, proto::connections::PayloadStatus status); // Converts the status of an endpoint that's been set out-of-band via a remote // ControlMessage to the PayloadStatus for handling of that endpoint-payload // pair. - static proto::connections::PayloadStatus endpointInfoStatusToPayloadStatus( - typename EndpointInfo::Status::Value status); + static proto::connections::PayloadStatus EndpointInfoStatusToPayloadStatus( + EndpointInfo::Status status); // Converts a ControlMessage::EventType for a particular payload to a // PayloadStatus. Called when we've received a ControlMessage with this event // from a remote endpoint; thus the PayloadStatuses are REMOTE_*. - static proto::connections::PayloadStatus controlMessageEventToPayloadStatus( + static proto::connections::PayloadStatus ControlMessageEventToPayloadStatus( PayloadTransferFrame::ControlMessage::EventType event); - static PayloadTransferUpdate::Status::Value - payloadStatusToTransferUpdateStatus(proto::connections::PayloadStatus status); + static PayloadProgressInfo::Status PayloadStatusToTransferUpdateStatus( + proto::connections::PayloadStatus status); - ConstPtr createPayloadHeader( - ConstPtr internal_payload); - ConstPtr createPayloadChunk( - std::int64_t payload_chunk_offset, - ConstPtr payload_chunk_body); + PayloadTransferFrame::PayloadHeader CreatePayloadHeader( + const InternalPayload& payload); + PayloadTransferFrame::PayloadChunk CreatePayloadChunk(std::int64_t offset, + ByteArray body); - Ptr createIncomingPayload( - const PayloadTransferFrame& payload_transfer_frame, - const string& endpoint_id); + PendingPayload* CreateIncomingPayload(const PayloadTransferFrame& frame, + const std::string& endpoint_id) + ABSL_LOCKS_EXCLUDED(mutex_); - void sendClientCallbacksForFinishedOutgoingPayload( - Ptr > client_proxy, - const std::vector& finished_endpoint_ids, + Payload::Id CreateOutgoingPayload(Payload payload, + const EndpointIds& endpoint_ids) + ABSL_LOCKS_EXCLUDED(mutex_); + + void SendClientCallbacksForFinishedOutgoingPayload( + ClientProxy* client, const EndpointIds& finished_endpoint_ids, const PayloadTransferFrame::PayloadHeader& payload_header, std::int64_t num_bytes_successfully_transferred, proto::connections::PayloadStatus status); - void sendClientCallbacksForFinishedIncomingPayload( - Ptr > client_proxy, const string& endpoint_id, + void SendClientCallbacksForFinishedIncomingPayload( + ClientProxy* client, const std::string& endpoint_id, const PayloadTransferFrame::PayloadHeader& payload_header, std::int64_t offset_bytes, proto::connections::PayloadStatus status); - void sendControlMessage( - const std::vector& endpoint_ids, + void SendControlMessage( + const EndpointIds& endpoint_ids, const PayloadTransferFrame::PayloadHeader& payload_header, std::int64_t num_bytes_successfully_transferred, PayloadTransferFrame::ControlMessage::EventType event_type); // Handles a finished outgoing payload for the given endpointIds. All statuses // except for SUCCESS are handled here. - void handleFinishedOutgoingPayload( - Ptr > client_proxy, - const std::vector& finished_endpoint_ids, + void HandleFinishedOutgoingPayload( + ClientProxy* client, const EndpointIds& finished_endpoint_ids, const PayloadTransferFrame::PayloadHeader& payload_header, std::int64_t num_bytes_successfully_transferred, - proto::connections::PayloadStatus status); - void handleFinishedIncomingPayload( - Ptr > client_proxy, const string& endpoint_id, + proto::connections::PayloadStatus status = + proto::connections::PayloadStatus::UNKNOWN_PAYLOAD_STATUS); + void HandleFinishedIncomingPayload( + ClientProxy* client, const std::string& endpoint_id, const PayloadTransferFrame::PayloadHeader& payload_header, std::int64_t offset_bytes, proto::connections::PayloadStatus status); - void handleSuccessfulOutgoingChunk( - Ptr > client_proxy, const string& endpoint_id, + void HandleSuccessfulOutgoingChunk( + ClientProxy* client, const std::string& endpoint_id, const PayloadTransferFrame::PayloadHeader& payload_header, std::int32_t payload_chunk_flags, std::int64_t payload_chunk_offset, std::int64_t payload_chunk_body_size); - void handleSuccessfulIncomingChunk( - Ptr > client_proxy, const string& endpoint_id, + void HandleSuccessfulIncomingChunk( + ClientProxy* client, const std::string& endpoint_id, const PayloadTransferFrame::PayloadHeader& payload_header, std::int32_t payload_chunk_flags, std::int64_t payload_chunk_offset, std::int64_t payload_chunk_body_size); - void processDataPacket(Ptr > to_client_proxy, - const string& from_endpoint_id, - const PayloadTransferFrame& payload_transfer_frame); - void processControlPacket(Ptr > to_client_proxy, - const string& from_endpoint_id, - const PayloadTransferFrame& payload_transfer_frame); + void ProcessDataPacket(ClientProxy* to_client, + const std::string& from_endpoint_id, + PayloadTransferFrame& payload_transfer_frame); + void ProcessControlPacket(ClientProxy* to_client, + const std::string& from_endpoint_id, + PayloadTransferFrame& payload_transfer_frame); // @PayloadStatusUpdateThread - void notifyClientOfIncomingPayloadTransferUpdate( - Ptr > client_proxy, const string& endpoint_id, - const PayloadTransferUpdate& payload_transfer_update, - bool done_with_payload); + void NotifyClientOfIncomingPayloadProgressInfo( + ClientProxy* client, const std::string& endpoint_id, + const PayloadProgressInfo& payload_transfer_update); - Ptr getOutgoingPayloadExecutor( - Payload::Type::Value payload_type); + SingleThreadExecutor* GetOutgoingPayloadExecutor(Payload::Type payload_type); - void enqueueOutgoingPayload( - Ptr executor, - Ptr runnable); + void RunOnStatusUpdateThread(std::function runnable); + bool NotifyShutdown() ABSL_LOCKS_EXCLUDED(mutex_); + void DestroyPendingPayload(Payload::Id payload_id) + ABSL_LOCKS_EXCLUDED(mutex_); + PendingPayload* GetPayload(Payload::Id payload_id) const + ABSL_LOCKS_EXCLUDED(mutex_); + void CancelAllPayloads() ABSL_LOCKS_EXCLUDED(mutex_); - ScopedPtr > > internal_payload_factory_; - ScopedPtr > send_payload_loop_runner_; - ScopedPtr > pending_payloads_; + mutable Mutex mutex_; + EndpointManager::FrameProcessor::Handle handle_; + AtomicBoolean shutdown_{false}; + std::unique_ptr shutdown_barrier_; + int send_payload_count_ = 0; + PendingPayloads pending_payloads_ ABSL_GUARDED_BY(mutex_); + SingleThreadExecutor bytes_payload_executor_; + SingleThreadExecutor file_payload_executor_; + SingleThreadExecutor stream_payload_executor_; + SingleThreadExecutor payload_status_update_executor_; - ScopedPtr > - bytes_payload_executor_; - ScopedPtr > - file_payload_executor_; - ScopedPtr > - stream_payload_executor_; - ScopedPtr > - payload_status_update_executor_; - - Ptr > endpoint_manager_; - std::shared_ptr self_{this, [](void*){}}; + EndpointManager* endpoint_manager_; }; } // namespace connections } // namespace nearby } // namespace location -#include "core/internal/payload_manager.cc" - #endif // CORE_INTERNAL_PAYLOAD_MANAGER_H_ diff --git a/cpp/core_v2/internal/payload_manager_test.cc b/cpp/core/internal/payload_manager_test.cc similarity index 97% rename from cpp/core_v2/internal/payload_manager_test.cc rename to cpp/core/internal/payload_manager_test.cc index bf843881..4e3b99db 100644 --- a/cpp/core_v2/internal/payload_manager_test.cc +++ b/cpp/core/internal/payload_manager_test.cc @@ -1,9 +1,9 @@ -#include "core_v2/internal/payload_manager.h" +#include "core/internal/payload_manager.h" -#include "core_v2/internal/simulation_user.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/public/pipe.h" -#include "platform_v2/public/system_clock.h" +#include "core/internal/simulation_user.h" +#include "platform/base/byte_array.h" +#include "platform/public/pipe.h" +#include "platform/public/system_clock.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/strings/string_view.h" diff --git a/cpp/core/internal/pcp.h b/cpp/core/internal/pcp.h index 427d974f..e752b862 100644 --- a/cpp/core/internal/pcp.h +++ b/cpp/core/internal/pcp.h @@ -5,15 +5,20 @@ namespace location { namespace nearby { namespace connections { -struct PCP { - enum Value { - UNKNOWN = 0, - P2P_STAR = 1, - P2P_CLUSTER = 2, - P2P_POINT_TO_POINT = 3, - }; +// The PreConnectionProtocol (PCP) defines the combinations of interactions +// between the techniques (ultrasound audio, Bluetooth device names, BLE +// advertisements) used for offline Advertisement + Discovery, and identifies +// the steps to go through on each device. +// +// See go/nearby-offline-data-interchange-formats for more. +enum class Pcp { + kUnknown = 0, + kP2pStar = 1, + kP2pCluster = 2, + kP2pPointToPoint = 3, + // PCP is only allocated 5 bits in our data interchange formats, so there can + // never be more than 31 PCP values. }; - } // namespace connections } // namespace nearby } // namespace location diff --git a/cpp/core/internal/pcp_handler.h b/cpp/core/internal/pcp_handler.h index 4babed34..197e081e 100644 --- a/cpp/core/internal/pcp_handler.h +++ b/cpp/core/internal/pcp_handler.h @@ -7,53 +7,99 @@ #include "core/internal/pcp.h" #include "core/listeners.h" #include "core/options.h" +#include "core/params.h" #include "core/status.h" #include "core/strategy.h" -#include "platform/port/string.h" #include "proto/connections_enums.pb.h" namespace location { namespace nearby { namespace connections { +inline Pcp StrategyToPcp(Strategy strategy) { + if (strategy == Strategy::kP2pCluster) return Pcp::kP2pCluster; + if (strategy == Strategy::kP2pStar) return Pcp::kP2pStar; + if (strategy == Strategy::kP2pPointToPoint) return Pcp::kP2pPointToPoint; + return Pcp::kUnknown; +} + +inline Strategy PcpToStrategy(Pcp pcp) { + if (pcp == Pcp::kP2pCluster) return Strategy::kP2pCluster; + if (pcp == Pcp::kP2pStar) return Strategy::kP2pStar; + if (pcp == Pcp::kP2pPointToPoint) return Strategy::kP2pPointToPoint; + return Strategy::kNone; +} + // Defines the set of methods that need to be implemented to handle the // per-PCP-specific operations in the OfflineServiceController. // -//

These methods are all meant to be synchronous, and should return only -// after knowing they've done what they were supposed to do (or unequivocally -// failed to do so). -template -class PCPHandler { +// These methods are all meant to be synchronous, and should return only after +// knowing they've done what they were supposed to do (or unequivocally failed +// to do so). +// +// See details here: +// https://source.corp.google.com/piper///depot/google3/core/core.h +class PcpHandler { public: - virtual ~PCPHandler() {} + virtual ~PcpHandler() = default; - virtual Strategy getStrategy() = 0; - virtual PCP::Value getPCP() = 0; + // Return strategy supported by this protocol. + virtual Strategy GetStrategy() const = 0; - virtual Status::Value startAdvertising( - Ptr > client_proxy, const string& service_id, - const string& local_endpoint_name, - const AdvertisingOptions& advertising_options, - Ptr connection_lifecycle_listener) = 0; - virtual void stopAdvertising(Ptr > client_proxy) = 0; + // Return concrete variant of protocol. + virtual Pcp GetPcp() const = 0; - virtual Status::Value startDiscovery( - Ptr > client_proxy, const string& service_id, - const DiscoveryOptions& discovery_options, - Ptr discovery_listener) = 0; - virtual void stopDiscovery(Ptr > client_proxy) = 0; + // We have been asked by the client to start advertising. Once we successfully + // start advertising, we'll change the ClientProxy's state. + // ConnectionListener (info.listener) will be notified in case of any event. + // See + // https://source.corp.google.com/piper///depot/google3/core/listeners.h;bpv=1;bpt=1;l=71?gsn=ConnectionListener + virtual Status StartAdvertising(ClientProxy* client, + const std::string& service_id, + const ConnectionOptions& options, + const ConnectionRequestInfo& info) = 0; - virtual Status::Value requestConnection( - Ptr > client_proxy, - const string& local_endpoint_name, const string& endpoint_id, - Ptr connection_lifecycle_listener) = 0; - virtual Status::Value acceptConnection( - Ptr > clientProxy, const string& endpoint_id, - Ptr payload_listener) = 0; - virtual Status::Value rejectConnection( - Ptr > client_proxy, const string& endpoint_id) = 0; + // If Advertising is active, stop it, and change CLientProxy state, + // otherwise do nothing. + virtual void StopAdvertising(ClientProxy* client) = 0; - virtual proto::connections::Medium getBandwidthUpgradeMedium() = 0; + // Start discovery of endpoints that may be advertising. + // Update ClientProxy state once discovery started. + // DiscoveryListener will get called in case of any event. + virtual Status StartDiscovery(ClientProxy* client, + const std::string& service_id, + const ConnectionOptions& options, + const DiscoveryListener& listener) = 0; + + // If Discovery is active, stop it, and change CLientProxy state, + // otherwise do nothing. + virtual void StopDiscovery(ClientProxy* client) = 0; + + // If Discovery is active with is_out_of_band_connection == true, invoke the + // callback with the provided endpoint info. + virtual void InjectEndpoint(ClientProxy* client, + const std::string& service_id, + const OutOfBandConnectionMetadata& metadata) = 0; + + // If remote endpoint has been successfully discovered, request it to form a + // connection, update state on ClientProxy. + virtual Status RequestConnection(ClientProxy* client, + const std::string& endpoint_id, + const ConnectionRequestInfo& info, + const ConnectionOptions& options) = 0; + + // Either party may call this to accept connection on their part. + // Until both parties call it, connection will not reach a data phase. + // Update state in ClientProxy. + virtual Status AcceptConnection(ClientProxy* client, + const std::string& endpoint_id, + const PayloadListener& payload_listener) = 0; + + // Either party may call this to reject connection on their part before + // connection reaches data phase. If either party does call it, connection + // will terminate. Update state in ClientProxy. + virtual Status RejectConnection(ClientProxy* client, + const std::string& endpoint_id) = 0; }; } // namespace connections diff --git a/cpp/core/internal/pcp_manager.cc b/cpp/core/internal/pcp_manager.cc index 2411ee39..d896048b 100644 --- a/cpp/core/internal/pcp_manager.cc +++ b/cpp/core/internal/pcp_manager.cc @@ -3,156 +3,123 @@ #include "core/internal/p2p_cluster_pcp_handler.h" #include "core/internal/p2p_point_to_point_pcp_handler.h" #include "core/internal/p2p_star_pcp_handler.h" +#include "core/internal/pcp_handler.h" namespace location { namespace nearby { namespace connections { -template -PCPManager::PCPManager( - Ptr > medium_manager, - Ptr endpoint_channel_manager, - Ptr > endpoint_manager, - Ptr bandwidth_upgrade_manager) - : pcp_handlers_(), current_pcp_handler_() { - pcp_handlers_[PCP::P2P_CLUSTER] = MakePtr(new P2PClusterPCPHandler( - medium_manager, endpoint_manager, endpoint_channel_manager, - bandwidth_upgrade_manager)); - pcp_handlers_[PCP::P2P_STAR] = MakePtr(new P2PStarPCPHandler( - medium_manager, endpoint_manager, endpoint_channel_manager, - bandwidth_upgrade_manager)); - pcp_handlers_[PCP::P2P_POINT_TO_POINT] = - MakePtr(new P2PPointToPointPCPHandler( - medium_manager, endpoint_manager, endpoint_channel_manager, - bandwidth_upgrade_manager)); +PcpManager::PcpManager(Mediums& mediums, + EndpointChannelManager& channel_manager, + EndpointManager& endpoint_manager, + BwuManager& bwu_manager) { + handlers_[Pcp::kP2pCluster] = std::make_unique( + &mediums, &endpoint_manager, &channel_manager, &bwu_manager); + handlers_[Pcp::kP2pStar] = std::make_unique( + mediums, endpoint_manager, channel_manager, bwu_manager); + handlers_[Pcp::kP2pPointToPoint] = + std::make_unique(mediums, endpoint_manager, + channel_manager, bwu_manager); } -template -PCPManager::~PCPManager() { - // TODO(tracyzhou): Add logging. - - // clear() instead of destroy() because this is just a reference -- the real - // object will be destroyed in the loop below. - current_pcp_handler_.clear(); - - for (typename PCPHandlersMap::iterator it = pcp_handlers_.begin(); - it != pcp_handlers_.end(); it++) { - it->second.destroy(); - } - pcp_handlers_.clear(); -} - -template -Status::Value PCPManager::startAdvertising( - Ptr > client_proxy, const string& endpoint_name, - const string& service_id, const AdvertisingOptions& advertising_options, - Ptr connection_lifecycle_listener) { - if (!setCurrentPCPHandler(advertising_options.strategy)) { - return Status::ERROR; - } - - return current_pcp_handler_->startAdvertising( - client_proxy, service_id, endpoint_name, advertising_options, - connection_lifecycle_listener); -} - -template -void PCPManager::stopAdvertising( - Ptr > client_proxy) { - if (!current_pcp_handler_.isNull()) { - current_pcp_handler_->stopAdvertising(client_proxy); +void PcpManager::DisconnectFromEndpointManager() { + if (shutdown_.Set(true)) return; + for (auto& item : handlers_) { + if (!item.second) continue; + item.second->DisconnectFromEndpointManager(); } } -template -Status::Value PCPManager::startDiscovery( - Ptr > client_proxy, const string& service_id, - const DiscoveryOptions& discovery_options, - Ptr discovery_listener) { - if (!setCurrentPCPHandler(discovery_options.strategy)) { - return Status::ERROR; - } - - return current_pcp_handler_->startDiscovery( - client_proxy, service_id, discovery_options, discovery_listener); +PcpManager::~PcpManager() { + DisconnectFromEndpointManager(); } -template -void PCPManager::stopDiscovery( - Ptr > client_proxy) { - if (!current_pcp_handler_.isNull()) { - current_pcp_handler_->stopDiscovery(client_proxy); +Status PcpManager::StartAdvertising(ClientProxy* client, + const string& service_id, + const ConnectionOptions& options, + const ConnectionRequestInfo& info) { + if (!SetCurrentPcpHandler(options.strategy)) { + return {Status::kError}; + } + + return current_->StartAdvertising(client, service_id, options, info); +} + +void PcpManager::StopAdvertising(ClientProxy* client) { + if (current_) { + current_->StopAdvertising(client); } } -template -Status::Value PCPManager::requestConnection( - Ptr > client_proxy, const string& endpoint_name, - const string& endpoint_id, - Ptr connection_lifecycle_listener) { - if (current_pcp_handler_.isNull()) { - return Status::OUT_OF_ORDER_API_CALL; +Status PcpManager::StartDiscovery(ClientProxy* client, const string& service_id, + const ConnectionOptions& options, + DiscoveryListener listener) { + if (!SetCurrentPcpHandler(options.strategy)) { + return {Status::kError}; } - return current_pcp_handler_->requestConnection( - client_proxy, endpoint_name, endpoint_id, connection_lifecycle_listener); + return current_->StartDiscovery(client, service_id, options, + std::move(listener)); } -template -Status::Value PCPManager::acceptConnection( - Ptr > client_proxy, const string& endpoint_id, - Ptr payload_listener) { - if (current_pcp_handler_.isNull()) { - return Status::OUT_OF_ORDER_API_CALL; - } - - return current_pcp_handler_->acceptConnection(client_proxy, endpoint_id, - payload_listener); -} - -template -Status::Value PCPManager::rejectConnection( - Ptr > client_proxy, const string& endpoint_id) { - if (current_pcp_handler_.isNull()) { - return Status::OUT_OF_ORDER_API_CALL; - } - - return current_pcp_handler_->rejectConnection(client_proxy, endpoint_id); -} - -template -proto::connections::Medium PCPManager::getBandwidthUpgradeMedium() { - if (current_pcp_handler_.isNull()) { - return proto::connections::Medium::UNKNOWN_MEDIUM; - } - - return current_pcp_handler_->getBandwidthUpgradeMedium(); -} - -template -bool PCPManager::setCurrentPCPHandler(const Strategy& strategy) { - current_pcp_handler_ = getPCPHandler(deducePCP(strategy)); - - return !current_pcp_handler_.isNull(); -} - -template -PCP::Value PCPManager::deducePCP(const Strategy& strategy) { - if (Strategy::kP2PCluster == strategy) { - return PCP::P2P_CLUSTER; - } else if (Strategy::kP2PStar == strategy) { - return PCP::P2P_STAR; - } else if (Strategy::kP2PPointToPoint == strategy) { - return PCP::P2P_POINT_TO_POINT; - } else { - // TODO(tracyzhou): Add logging. - return PCP::UNKNOWN; +void PcpManager::StopDiscovery(ClientProxy* client) { + if (current_) { + current_->StopDiscovery(client); } } -template -Ptr > PCPManager::getPCPHandler(PCP::Value pcp) { - return pcp_handlers_[pcp]; +void PcpManager::InjectEndpoint(ClientProxy* client, + const std::string& service_id, + const OutOfBandConnectionMetadata& metadata) { + if (current_) { + current_->InjectEndpoint(client, service_id, metadata); + } +} + +Status PcpManager::RequestConnection(ClientProxy* client, + const string& endpoint_id, + const ConnectionRequestInfo& info, + const ConnectionOptions& options) { + if (!current_) { + return {Status::kOutOfOrderApiCall}; + } + + return current_->RequestConnection(client, endpoint_id, info, options); +} + +Status PcpManager::AcceptConnection(ClientProxy* client, + const string& endpoint_id, + const PayloadListener& payload_listener) { + if (!current_) { + return {Status::kOutOfOrderApiCall}; + } + + return current_->AcceptConnection(client, endpoint_id, payload_listener); +} + +Status PcpManager::RejectConnection(ClientProxy* client, + const string& endpoint_id) { + if (!current_) { + return {Status::kOutOfOrderApiCall}; + } + + return current_->RejectConnection(client, endpoint_id); +} + +bool PcpManager::SetCurrentPcpHandler(Strategy strategy) { + current_ = GetPcpHandler(StrategyToPcp(strategy)); + + if (!current_) { + NEARBY_LOG(ERROR, "Failed to set current PCP handler: strategy=%s", + strategy.GetName().c_str()); + } + + return current_; +} + +PcpHandler* PcpManager::GetPcpHandler(Pcp pcp) const { + auto item = handlers_.find(pcp); + return item != handlers_.end() ? item->second.get() : nullptr; } } // namespace connections diff --git a/cpp/core/internal/pcp_manager.h b/cpp/core/internal/pcp_manager.h index 731f6951..8e46e2cf 100644 --- a/cpp/core/internal/pcp_manager.h +++ b/cpp/core/internal/pcp_manager.h @@ -1,77 +1,73 @@ #ifndef CORE_INTERNAL_PCP_MANAGER_H_ #define CORE_INTERNAL_PCP_MANAGER_H_ -#include +#include -#include "core/internal/bandwidth_upgrade_manager.h" +#include "core/internal/base_pcp_handler.h" +#include "core/internal/bwu_manager.h" #include "core/internal/client_proxy.h" #include "core/internal/endpoint_channel_manager.h" #include "core/internal/endpoint_manager.h" -#include "core/internal/medium_manager.h" -#include "core/internal/pcp_handler.h" +#include "core/internal/mediums/mediums.h" #include "core/listeners.h" #include "core/options.h" #include "core/status.h" #include "core/strategy.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "platform/public/atomic_boolean.h" +#include "absl/container/flat_hash_map.h" namespace location { namespace nearby { namespace connections { -// Manages all known PCPHandler implementations, delegating operations to the +// Manages all known PcpHandler implementations, delegating operations to the // appropriate one as per the parameters passed in. // -//

This will only ever be used by the OfflineServiceController, which has all +// This will only ever be used by the OfflineServiceController, which has all // of its entrypoints invoked serially, so there's no synchronization needed. -template -class PCPManager { +// Public method semantics matches definition in the +// https://source.corp.google.com/piper///depot/google3/core/internal/service_controller.h +class PcpManager { public: - PCPManager(Ptr > medium_manager, - Ptr endpoint_channel_manager, - Ptr > endpoint_manager, - Ptr bandwidth_upgrade_manager); - ~PCPManager(); + PcpManager(Mediums& mediums, EndpointChannelManager& channel_manager, + EndpointManager& endpoint_manager, BwuManager& bwu_manager); + ~PcpManager(); - Status::Value startAdvertising( - Ptr > client_proxy, const string& endpoint_name, - const string& service_id, const AdvertisingOptions& advertising_options, - Ptr connection_lifecycle_listener); - void stopAdvertising(Ptr > client_proxy); + Status StartAdvertising(ClientProxy* client, const string& service_id, + const ConnectionOptions& options, + const ConnectionRequestInfo& info); + void StopAdvertising(ClientProxy* client); - Status::Value startDiscovery(Ptr > client_proxy, - const string& service_id, - const DiscoveryOptions& discovery_options, - Ptr discovery_listener); - void stopDiscovery(Ptr > client_proxy); + Status StartDiscovery(ClientProxy* client, const string& service_id, + const ConnectionOptions& options, + DiscoveryListener listener); + void StopDiscovery(ClientProxy* client); - Status::Value requestConnection( - Ptr > client_proxy, const string& endpoint_name, - const string& endpoint_id, - Ptr connection_lifecycle_listener); - Status::Value acceptConnection(Ptr > client_proxy, - const string& endpoint_id, - Ptr payload_listener); - Status::Value rejectConnection(Ptr > client_proxy, - const string& endpoint_id); + void InjectEndpoint(ClientProxy* client, + const std::string& service_id, + const OutOfBandConnectionMetadata& metadata); - proto::connections::Medium getBandwidthUpgradeMedium(); + Status RequestConnection(ClientProxy* client, const string& endpoint_id, + const ConnectionRequestInfo& info, + const ConnectionOptions& options); + Status AcceptConnection(ClientProxy* client, const string& endpoint_id, + const PayloadListener& payload_listener); + Status RejectConnection(ClientProxy* client, const string& endpoint_id); + + proto::connections::Medium GetBandwidthUpgradeMedium(); + void DisconnectFromEndpointManager(); private: - bool setCurrentPCPHandler(const Strategy& strategy); - PCP::Value deducePCP(const Strategy& strategy); - Ptr > getPCPHandler(PCP::Value pcp); + bool SetCurrentPcpHandler(Strategy strategy); + PcpHandler* GetPcpHandler(Pcp pcp) const; - typedef std::map > > PCPHandlersMap; - PCPHandlersMap pcp_handlers_; - Ptr > current_pcp_handler_; + AtomicBoolean shutdown_{false}; + absl::flat_hash_map> handlers_; + PcpHandler* current_ = nullptr; }; } // namespace connections } // namespace nearby } // namespace location -#include "core/internal/pcp_manager.cc" - #endif // CORE_INTERNAL_PCP_MANAGER_H_ diff --git a/cpp/core_v2/internal/pcp_manager_test.cc b/cpp/core/internal/pcp_manager_test.cc similarity index 81% rename from cpp/core_v2/internal/pcp_manager_test.cc rename to cpp/core/internal/pcp_manager_test.cc index ec261f8d..93b2979b 100644 --- a/cpp/core_v2/internal/pcp_manager_test.cc +++ b/cpp/core/internal/pcp_manager_test.cc @@ -1,12 +1,13 @@ -#include "core_v2/internal/pcp_manager.h" +#include "core/internal/pcp_manager.h" +#include #include -#include "core_v2/internal/endpoint_channel_manager.h" -#include "core_v2/internal/simulation_user.h" -#include "core_v2/options.h" -#include "platform_v2/base/medium_environment.h" -#include "platform_v2/public/count_down_latch.h" +#include "core/internal/endpoint_channel_manager.h" +#include "core/internal/simulation_user.h" +#include "core/options.h" +#include "platform/base/medium_environment.h" +#include "platform/public/count_down_latch.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/time/time.h" @@ -16,6 +17,7 @@ namespace nearby { namespace connections { namespace { +constexpr std::array kFakeMacAddress = {'a', 'b', 'c', 'd', 'e', 'f'}; constexpr char kServiceId[] = "service-id"; constexpr char kDeviceA[] = "device-A"; constexpr char kDeviceB[] = "device-B"; @@ -139,6 +141,24 @@ TEST_P(PcpManagerTest, CanReject) { INSTANTIATE_TEST_SUITE_P(ParametrisedPcpManagerTest, PcpManagerTest, ::testing::ValuesIn(kTestCases)); +// Verifies that InjectEndpoint() can be run successfully; does not test the +// full connection flow given that normal discovery/advertisement is skipped. +// Note: Not parameterized because InjectEndpoint only works over Bluetooth. +TEST_F(PcpManagerTest, InjectEndpoint) { + env_.Start(); + SimulationUser user_a(kDeviceA, + BooleanMediumSelector{.bluetooth = true}); + user_a.StartDiscovery(kServiceId, /*latch=*/nullptr); + user_a.InjectEndpoint( + kServiceId, + OutOfBandConnectionMetadata{ + .medium = Medium::BLUETOOTH, + .remote_bluetooth_mac_address = ByteArray(kFakeMacAddress), + }); + user_a.Stop(); + env_.Stop(); +} + } // namespace } // namespace connections } // namespace nearby diff --git a/cpp/core/internal/service_controller.h b/cpp/core/internal/service_controller.h index 05f37071..ecd80e8a 100644 --- a/cpp/core/internal/service_controller.h +++ b/cpp/core/internal/service_controller.h @@ -2,61 +2,75 @@ #define CORE_INTERNAL_SERVICE_CONTROLLER_H_ #include +#include #include #include "core/internal/client_proxy.h" #include "core/listeners.h" #include "core/options.h" +#include "core/params.h" #include "core/payload.h" #include "core/status.h" -#include "platform/port/string.h" -#include "platform/ptr.h" namespace location { namespace nearby { namespace connections { -template +// Interface defines the core functionality of Nearby Connections Service. +// +// In every method, ClientProxy* represents the client app which receives +// notifications from Nearby Connections service and forwards them to the app. +// ResultCallback arguments are not provided for this class, because all methods +// are called synchronously. +// The rest of arguments have the same meaning as the corresponding +// methods in the definition of location::nearby::Core API. +// +// See details here: +// https://source.corp.google.com/piper///depot/google3/core/core.h class ServiceController { public: - virtual ~ServiceController() {} + virtual ~ServiceController() = default; + ServiceController() = default; + ServiceController(const ServiceController&) = delete; + ServiceController& operator=(const ServiceController&) = delete; - virtual Status::Value startAdvertising( - Ptr > client_proxy, - const std::string& endpoint_name, const std::string& service_id, - const AdvertisingOptions& advertising_options, - Ptr connection_lifecycle_listener) = 0; - virtual void stopAdvertising(Ptr > client_proxy) = 0; + // Starts advertising an endpoint for a local app. + virtual Status StartAdvertising(ClientProxy* client, + const std::string& service_id, + const ConnectionOptions& options, + const ConnectionRequestInfo& info) = 0; + virtual void StopAdvertising(ClientProxy* client) = 0; - virtual Status::Value startDiscovery( - Ptr > client_proxy, const std::string& service_id, - const DiscoveryOptions& discovery_options, - Ptr discovery_listener) = 0; - virtual void stopDiscovery(Ptr > client_proxy) = 0; + virtual Status StartDiscovery(ClientProxy* client, + const std::string& service_id, + const ConnectionOptions& options, + const DiscoveryListener& listener) = 0; + virtual void StopDiscovery(ClientProxy* client) = 0; - virtual Status::Value requestConnection( - Ptr > client_proxy, - const std::string& endpoint_name, const std::string& endpoint_id, - Ptr connection_lifecycle_listener) = 0; - virtual Status::Value acceptConnection( - Ptr > client_proxy, const std::string& endpoint_id, - Ptr payload_listener) = 0; - virtual Status::Value rejectConnection( - Ptr > client_proxy, - const std::string& endpoint_id) = 0; + virtual void InjectEndpoint(ClientProxy* client, + const std::string& service_id, + const OutOfBandConnectionMetadata& metadata) = 0; - virtual void initiateBandwidthUpgrade( - Ptr > client_proxy, - const std::string& endpoint_id) = 0; + virtual Status RequestConnection(ClientProxy* client, + const std::string& endpoint_id, + const ConnectionRequestInfo& info, + const ConnectionOptions& options) = 0; + virtual Status AcceptConnection(ClientProxy* client, + const std::string& endpoint_id, + const PayloadListener& listener) = 0; + virtual Status RejectConnection(ClientProxy* client, + const std::string& endpoint_id) = 0; - virtual void sendPayload(Ptr > client_proxy, + virtual void InitiateBandwidthUpgrade(ClientProxy* client, + const std::string& endpoint_id) = 0; + + virtual void SendPayload(ClientProxy* client, const std::vector& endpoint_ids, - ConstPtr payload) = 0; + Payload payload) = 0; - virtual Status::Value cancelPayload(Ptr > client_proxy, - std::int64_t payload_id) = 0; + virtual Status CancelPayload(ClientProxy* client, Payload::Id payload_id) = 0; - virtual void disconnectFromEndpoint(Ptr > client_proxy, + virtual void DisconnectFromEndpoint(ClientProxy* client, const std::string& endpoint_id) = 0; }; diff --git a/cpp/core/internal/service_controller_router.cc b/cpp/core/internal/service_controller_router.cc index aa76330e..42fb263b 100644 --- a/cpp/core/internal/service_controller_router.cc +++ b/cpp/core/internal/service_controller_router.cc @@ -1,748 +1,425 @@ #include "core/internal/service_controller_router.h" -#include "core/internal/offline_service_controller.h" +#include +#include +#include +#include + +#include "core/internal/client_proxy.h" +#include "core/listeners.h" +#include "core/options.h" +#include "core/params.h" +#include "core/payload.h" +#include "platform/public/logging.h" +#include "absl/time/clock.h" namespace location { namespace nearby { namespace connections { +namespace { +const std::size_t kMacAddressLength = 6u; +} // namespace -namespace service_controller_router { - -// Base class for the following Runnable classes. They all need a -// ServiceControllerRouter object and a ClientProxy object. -// ServiceControllerRouter is kept as a reference because the passed in -// Ptr > should outlive it. -template -class ServiceControllerRouterRunnable : public Runnable { - protected: - ServiceControllerRouterRunnable( - Ptr > service_controller_router, - Ptr > client_proxy) - : service_controller_router_(service_controller_router), - client_proxy_(client_proxy) {} - - Ptr > service_controller_router_; - Ptr > client_proxy_; -}; - -template -class StartAdvertisingRunnable - : public ServiceControllerRouterRunnable { - public: - StartAdvertisingRunnable( - Ptr > service_controller_router, - Ptr > client_proxy, - ConstPtr start_advertising_params) - : ServiceControllerRouterRunnable(service_controller_router, - client_proxy), - params_(start_advertising_params) {} - - void run() override { - ScopedPtr > result_listener(params_->result_listener); - - Status::Value status = - this->service_controller_router_->acquireServiceControllerForClient( - this->client_proxy_, params_->advertising_options.strategy); - if (Status::SUCCESS != status) { - result_listener->onResult(status); - return; - } - - if (this->client_proxy_->isAdvertising()) { - result_listener->onResult(Status::ALREADY_ADVERTISING); - return; - } - - result_listener->onResult( - this->service_controller_router_->current_service_controller_ - ->startAdvertising(this->client_proxy_, params_->name, - params_->service_id, - params_->advertising_options, - params_->connection_lifecycle_listener)); - } - - private: - ScopedPtr > params_; -}; - -template -class StopAdvertisingRunnable - : public ServiceControllerRouterRunnable { - public: - StopAdvertisingRunnable( - Ptr > service_controller_router, - Ptr > client_proxy, - ConstPtr stop_advertising_params) - : ServiceControllerRouterRunnable(service_controller_router, - client_proxy), - params_(stop_advertising_params) {} - - void run() override { - if (this->service_controller_router_->clientHasAquiredServiceController( - this->client_proxy_) && - this->client_proxy_->isAdvertising()) { - this->service_controller_router_->current_service_controller_ - ->stopAdvertising(this->client_proxy_); - } - } - - private: - ScopedPtr > params_; -}; - -template -class StartDiscoveryRunnable - : public ServiceControllerRouterRunnable { - public: - StartDiscoveryRunnable( - Ptr > service_controller_router, - Ptr > client_proxy, - ConstPtr start_discovery_params) - : ServiceControllerRouterRunnable(service_controller_router, - client_proxy), - params_(start_discovery_params) {} - - void run() override { - ScopedPtr > result_listener(params_->result_listener); - - Status::Value status = - this->service_controller_router_->acquireServiceControllerForClient( - this->client_proxy_, params_->discovery_options.strategy); - if (Status::SUCCESS != status) { - result_listener->onResult(status); - return; - } - - if (this->client_proxy_->isDiscovering()) { - result_listener->onResult(Status::ALREADY_DISCOVERING); - return; - } - - result_listener->onResult( - this->service_controller_router_->current_service_controller_ - ->startDiscovery(this->client_proxy_, params_->service_id, - params_->discovery_options, - params_->discovery_listener)); - } - - private: - ScopedPtr > params_; -}; - -template -class StopDiscoveryRunnable : public ServiceControllerRouterRunnable { - public: - StopDiscoveryRunnable( - Ptr > service_controller_router, - Ptr > client_proxy, - ConstPtr stop_discovery_params) - : ServiceControllerRouterRunnable(service_controller_router, - client_proxy), - params_(stop_discovery_params) {} - - void run() override { - if (this->service_controller_router_->clientHasAquiredServiceController( - this->client_proxy_) && - this->client_proxy_->isDiscovering()) { - this->service_controller_router_->current_service_controller_ - ->stopDiscovery(this->client_proxy_); - } - } - - private: - ScopedPtr > params_; -}; - -template -class SendConnectionRequestRunnable - : public ServiceControllerRouterRunnable { - public: - SendConnectionRequestRunnable( - Ptr > service_controller_router, - Ptr > client_proxy, - ConstPtr request_connection_params) - : ServiceControllerRouterRunnable(service_controller_router, - client_proxy), - params_(request_connection_params) {} - - void run() override { - ScopedPtr > result_listener(params_->result_listener); - - if (!this->service_controller_router_->clientHasAquiredServiceController( - this->client_proxy_)) { - result_listener->onResult(Status::OUT_OF_ORDER_API_CALL); - return; - } - - const string& remote_endpoint_id = params_->remote_endpoint_id; - - if (this->client_proxy_->hasPendingConnectionToEndpoint( - remote_endpoint_id) || - this->client_proxy_->isConnectedToEndpoint(remote_endpoint_id)) { - result_listener->onResult(Status::ALREADY_CONNECTED_TO_ENDPOINT); - return; - } - - result_listener->onResult( - this->service_controller_router_->current_service_controller_ - ->requestConnection(this->client_proxy_, params_->name, - remote_endpoint_id, - params_->connection_lifecycle_listener)); - } - - private: - ScopedPtr > params_; -}; - -template -class AcceptConnectionRequestRunnable - : public ServiceControllerRouterRunnable { - public: - AcceptConnectionRequestRunnable( - Ptr > service_controller_router, - Ptr > client_proxy, - ConstPtr accept_connection_params) - : ServiceControllerRouterRunnable(service_controller_router, - client_proxy), - params_(accept_connection_params) {} - - void run() override { - ScopedPtr > result_listener(params_->result_listener); - - if (!this->service_controller_router_->clientHasAquiredServiceController( - this->client_proxy_)) { - result_listener->onResult(Status::OUT_OF_ORDER_API_CALL); - return; - } - - const string& remote_endpoint_id = params_->remote_endpoint_id; - - if (this->client_proxy_->isConnectedToEndpoint(remote_endpoint_id)) { - result_listener->onResult(Status::ALREADY_CONNECTED_TO_ENDPOINT); - return; - } - - if (this->client_proxy_->hasLocalEndpointResponded(remote_endpoint_id)) { - // TODO(tracyzhou): logging - result_listener->onResult(Status::OUT_OF_ORDER_API_CALL); - return; - } - - result_listener->onResult( - this->service_controller_router_->current_service_controller_ - ->acceptConnection(this->client_proxy_, remote_endpoint_id, - params_->payload_listener)); - } - - private: - ScopedPtr > params_; -}; - -template -class RejectConnectionRequestRunnable - : public ServiceControllerRouterRunnable { - public: - RejectConnectionRequestRunnable( - Ptr > service_controller_router, - Ptr > client_proxy, - ConstPtr reject_connection_params) - : ServiceControllerRouterRunnable(service_controller_router, - client_proxy), - params_(reject_connection_params) {} - - void run() override { - ScopedPtr > result_listener(params_->result_listener); - - if (!this->service_controller_router_->clientHasAquiredServiceController( - this->client_proxy_)) { - result_listener->onResult(Status::OUT_OF_ORDER_API_CALL); - return; - } - - const string& remote_endpoint_id = params_->remote_endpoint_id; - - if (this->client_proxy_->isConnectedToEndpoint(remote_endpoint_id)) { - result_listener->onResult(Status::ALREADY_CONNECTED_TO_ENDPOINT); - return; - } - - if (this->client_proxy_->hasLocalEndpointResponded(remote_endpoint_id)) { - // TODO(tracyzhou): logging - result_listener->onResult(Status::OUT_OF_ORDER_API_CALL); - return; - } - - result_listener->onResult( - this->service_controller_router_->current_service_controller_ - ->rejectConnection(this->client_proxy_, remote_endpoint_id)); - } - - private: - ScopedPtr > params_; -}; - -template -class InitiateBandwidthUpgradeRunnable - : public ServiceControllerRouterRunnable { - public: - InitiateBandwidthUpgradeRunnable( - Ptr > service_controller_router, - Ptr > client_proxy, - ConstPtr - initiate_bandwidth_upgrade_params) - : ServiceControllerRouterRunnable(service_controller_router, - client_proxy), - params_(initiate_bandwidth_upgrade_params) {} - - void run() override { - ScopedPtr > result_listener(params_->result_listener); - - if (!this->service_controller_router_->clientHasAquiredServiceController( - this->client_proxy_) || - !this->client_proxy_->isConnectedToEndpoint( - params_->remote_endpoint_id)) { - result_listener->onResult(Status::OUT_OF_ORDER_API_CALL); - return; - } - - this->service_controller_router_->current_service_controller_ - ->initiateBandwidthUpgrade(this->client_proxy_, - params_->remote_endpoint_id); - - // The caller can listen to - // ConnectionLifecycleListener.onBandwidthChanged() to determine success. - result_listener->onResult(Status::SUCCESS); - } - - private: - ScopedPtr > params_; -}; - -template -class SendPayloadRunnable : public ServiceControllerRouterRunnable { - public: - SendPayloadRunnable( - Ptr > service_controller_router, - Ptr > client_proxy, - ConstPtr send_payload_params) - : ServiceControllerRouterRunnable(service_controller_router, - client_proxy), - params_(send_payload_params) {} - - void run() override { - ScopedPtr > result_listener(params_->result_listener); - - if (!this->service_controller_router_->clientHasAquiredServiceController( - this->client_proxy_)) { - result_listener->onResult(Status::OUT_OF_ORDER_API_CALL); - return; - } - - if (!ServiceControllerRouter:: - clientHasConnectionToAtLeastOneEndpoint( - this->client_proxy_, params_->remote_endpoint_ids)) { - result_listener->onResult(Status::ENDPOINT_UNKNOWN); - return; - } - - this->service_controller_router_->current_service_controller_->sendPayload( - this->client_proxy_, params_->remote_endpoint_ids, params_->payload); - - // At this point, we've queued up the send Payload request with the - // ServiceController; any further failures (e.g. one of the endpoints is - // unknown, goes away, or otherwise fails) will be returned to the client - // as a PayloadTransferUpdate. - result_listener->onResult(Status::SUCCESS); - } - - private: - ScopedPtr > params_; -}; - -template -class CancelPayloadRunnable : public ServiceControllerRouterRunnable { - public: - CancelPayloadRunnable( - Ptr > service_controller_router, - Ptr > client_proxy, - ConstPtr cancel_payload_params) - : ServiceControllerRouterRunnable(service_controller_router, - client_proxy), - params_(cancel_payload_params) {} - - void run() override { - ScopedPtr > result_listener(params_->result_listener); - - if (!this->service_controller_router_->clientHasAquiredServiceController( - this->client_proxy_)) { - result_listener->onResult(Status::OUT_OF_ORDER_API_CALL); - return; - } - - result_listener->onResult( - this->service_controller_router_->current_service_controller_ - ->cancelPayload(this->client_proxy_, params_->payload_id)); - } - - private: - ScopedPtr > params_; -}; - -template -class DisconnectFromEndpointRunnable - : public ServiceControllerRouterRunnable { - public: - DisconnectFromEndpointRunnable( - Ptr > service_controller_router, - Ptr > client_proxy, - ConstPtr disconnect_from_endpoint_params) - : ServiceControllerRouterRunnable(service_controller_router, - client_proxy), - params_(disconnect_from_endpoint_params) {} - - void run() override { - if (this->service_controller_router_->clientHasAquiredServiceController( - this->client_proxy_)) { - const string& remote_endpoint_id = params_->remote_endpoint_id; - - if (!this->client_proxy_->isConnectedToEndpoint(remote_endpoint_id) && - !this->client_proxy_->hasPendingConnectionToEndpoint( - remote_endpoint_id)) { - return; - } - this->service_controller_router_->current_service_controller_ - ->disconnectFromEndpoint(this->client_proxy_, remote_endpoint_id); - } - } - - private: - ScopedPtr > params_; -}; - -template -class StopAllEndpointsRunnable - : public ServiceControllerRouterRunnable { - public: - StopAllEndpointsRunnable( - Ptr > service_controller_router, - Ptr > client_proxy, - ConstPtr stop_all_endpoints_params) - : ServiceControllerRouterRunnable(service_controller_router, - client_proxy), - params_(stop_all_endpoints_params) {} - - void run() override { - ScopedPtr > result_listener(params_->result_listener); - - if (this->service_controller_router_->clientHasAquiredServiceController( - this->client_proxy_)) { - this->service_controller_router_->doneWithStrategySessionForClient( - this->client_proxy_); - } - result_listener->onResult(Status::SUCCESS); - } - - private: - ScopedPtr > params_; -}; - -template -class ClientDisconnectingRunnable - : public ServiceControllerRouterRunnable { - public: - ClientDisconnectingRunnable( - Ptr> service_controller_router, - Ptr> client_proxy) - : ServiceControllerRouterRunnable(service_controller_router, - client_proxy) {} - - void run() override { - if (!this->service_controller_router_->clientHasAquiredServiceController( - this->client_proxy_)) { - return; - } - - this->service_controller_router_->doneWithStrategySessionForClient( - this->client_proxy_); - - // Log the completion of this client's connection. - // TODO(tracyzhou): Add logging. - } -}; - -} // namespace service_controller_router - -template -ServiceControllerRouter::ServiceControllerRouter() - : current_service_controller_clients_(), - current_service_controller_(new OfflineServiceController()), - current_strategy_(), - serializer_(Platform::createSingleThreadExecutor()) {} - -template -ServiceControllerRouter::~ServiceControllerRouter() { - // TODO(tracyzhou): Add logging. +ServiceControllerRouter::~ServiceControllerRouter() { + NEARBY_LOG(INFO, "ServiceControllerRouter going down."); // And make sure that cleanup is the last thing we do. - serializer_->shutdown(); - - current_service_controller_.destroy(); - current_strategy_.destroy(); - current_service_controller_clients_.clear(); + serializer_.Shutdown(); } -template -void ServiceControllerRouter::startAdvertising( - Ptr > client_proxy, - ConstPtr start_advertising_params) { - routeToServiceController( - MakePtr(new service_controller_router::StartAdvertisingRunnable( - self_, client_proxy, start_advertising_params))); +void ServiceControllerRouter::StartAdvertising( + ClientProxy* client, absl::string_view service_id, + const ConnectionOptions& options, const ConnectionRequestInfo& info, + const ResultCallback& callback) { + RouteToServiceController([this, client, service_id = std::string(service_id), + options, info, callback]() { + Status status = AcquireServiceControllerForClient(client, options.strategy); + if (!status.Ok()) { + callback.result_cb(status); + return; + } + + if (client->IsAdvertising()) { + callback.result_cb({Status::kAlreadyAdvertising}); + return; + } + + status = service_controller_->StartAdvertising(client, service_id, options, + info); + callback.result_cb(status); + }); } -template -void ServiceControllerRouter::stopAdvertising( - Ptr > client_proxy, - ConstPtr stop_advertising_params) { - routeToServiceController( - MakePtr(new service_controller_router::StopAdvertisingRunnable( - self_, client_proxy, stop_advertising_params))); +void ServiceControllerRouter::StopAdvertising(ClientProxy* client, + const ResultCallback& callback) { + RouteToServiceController([this, client, callback]() { + if (ClientHasAcquiredServiceController(client) && client->IsAdvertising()) { + service_controller_->StopAdvertising(client); + } + callback.result_cb({Status::kSuccess}); + }); } -template -void ServiceControllerRouter::startDiscovery( - Ptr > client_proxy, - ConstPtr start_discovery_params) { - routeToServiceController( - MakePtr(new service_controller_router::StartDiscoveryRunnable( - self_, client_proxy, start_discovery_params))); +void ServiceControllerRouter::StartDiscovery(ClientProxy* client, + absl::string_view service_id, + const ConnectionOptions& options, + const DiscoveryListener& listener, + const ResultCallback& callback) { + RouteToServiceController([this, client, service_id = std::string(service_id), + options, listener, callback]() { + Status status = AcquireServiceControllerForClient(client, options.strategy); + if (!status.Ok()) { + callback.result_cb(status); + return; + } + + if (client->IsDiscovering()) { + callback.result_cb({Status::kAlreadyDiscovering}); + return; + } + + status = service_controller_->StartDiscovery(client, service_id, options, + listener); + callback.result_cb(status); + }); } -template -void ServiceControllerRouter::stopDiscovery( - Ptr > client_proxy, - ConstPtr stop_discovery_params) { - routeToServiceController( - MakePtr(new service_controller_router::StopDiscoveryRunnable( - self_, client_proxy, stop_discovery_params))); +void ServiceControllerRouter::StopDiscovery(ClientProxy* client, + const ResultCallback& callback) { + RouteToServiceController([this, client, callback]() { + if (ClientHasAcquiredServiceController(client) && client->IsDiscovering()) { + service_controller_->StopDiscovery(client); + } + callback.result_cb({Status::kSuccess}); + }); } -template -void ServiceControllerRouter::requestConnection( - Ptr > client_proxy, - ConstPtr request_connection_params) { - routeToServiceController(MakePtr( - new service_controller_router::SendConnectionRequestRunnable( - self_, client_proxy, request_connection_params))); +void ServiceControllerRouter::InjectEndpoint( + ClientProxy* client, absl::string_view service_id, + const OutOfBandConnectionMetadata& metadata, + const ResultCallback& callback) { + RouteToServiceController( + [this, client, service_id = std::string(service_id), metadata, + callback]() { + // Currently, Bluetooth is the only supported medium for endpoint injection. + if (metadata.medium != Medium::BLUETOOTH || + metadata.remote_bluetooth_mac_address.size() != kMacAddressLength) { + callback.result_cb({Status::kError}); + return; + } + + if (!ClientHasAcquiredServiceController(client) || + !client->IsDiscovering()) { + callback.result_cb({Status::kOutOfOrderApiCall}); + return; + } + + service_controller_->InjectEndpoint(client, service_id, metadata); + callback.result_cb({Status::kSuccess}); + }); } -template -void ServiceControllerRouter::acceptConnection( - Ptr > client_proxy, - ConstPtr accept_connection_params) { - routeToServiceController(MakePtr( - new service_controller_router::AcceptConnectionRequestRunnable( - self_, client_proxy, accept_connection_params))); +void ServiceControllerRouter::RequestConnection( + ClientProxy* client, absl::string_view endpoint_id, + const ConnectionRequestInfo& info, const ConnectionOptions& options, + const ResultCallback& callback) { + RouteToServiceController([this, client, + endpoint_id = std::string(endpoint_id), info, + options, callback]() { + if (!ClientHasAcquiredServiceController(client)) { + callback.result_cb({Status::kOutOfOrderApiCall}); + return; + } + + if (client->HasPendingConnectionToEndpoint(endpoint_id) || + client->IsConnectedToEndpoint(endpoint_id)) { + callback.result_cb({Status::kAlreadyConnectedToEndpoint}); + return; + } + + callback.result_cb(service_controller_->RequestConnection( + client, endpoint_id, info, options)); + }); } -template -void ServiceControllerRouter::rejectConnection( - Ptr > client_proxy, - ConstPtr reject_connection_params) { - routeToServiceController(MakePtr( - new service_controller_router::RejectConnectionRequestRunnable( - self_, client_proxy, reject_connection_params))); +void ServiceControllerRouter::AcceptConnection(ClientProxy* client, + absl::string_view endpoint_id, + const PayloadListener& listener, + const ResultCallback& callback) { + RouteToServiceController([this, client, + endpoint_id = std::string(endpoint_id), listener, + callback]() { + if (!ClientHasAcquiredServiceController(client)) { + callback.result_cb({Status::kOutOfOrderApiCall}); + return; + } + + if (client->IsConnectedToEndpoint(endpoint_id)) { + callback.result_cb({Status::kAlreadyConnectedToEndpoint}); + return; + } + + if (client->HasLocalEndpointResponded(endpoint_id)) { + NEARBY_LOG(INFO, + "[ServiceControllerRouter:Accept]: Client has local " + "endpoint responded; id=%s", + endpoint_id.c_str()); + callback.result_cb({Status::kOutOfOrderApiCall}); + return; + } + + callback.result_cb( + service_controller_->AcceptConnection(client, endpoint_id, listener)); + }); } -template -void ServiceControllerRouter::initiateBandwidthUpgrade( - Ptr > client_proxy, - ConstPtr - initiate_bandwidth_upgrade_params) { - routeToServiceController(MakePtr( - new service_controller_router::InitiateBandwidthUpgradeRunnable( - self_, client_proxy, initiate_bandwidth_upgrade_params))); +void ServiceControllerRouter::RejectConnection(ClientProxy* client, + absl::string_view endpoint_id, + const ResultCallback& callback) { + RouteToServiceController( + [this, client, endpoint_id = std::string(endpoint_id), callback]() { + if (!ClientHasAcquiredServiceController(client)) { + callback.result_cb({Status::kOutOfOrderApiCall}); + return; + } + + if (client->IsConnectedToEndpoint(endpoint_id)) { + callback.result_cb({Status::kAlreadyConnectedToEndpoint}); + return; + } + + if (client->HasLocalEndpointResponded(endpoint_id)) { + NEARBY_LOG(INFO, + "[ServiceControllerRouter:Reject]: Client has local " + "endpoint responded; id=%s", + endpoint_id.c_str()); + callback.result_cb({Status::kOutOfOrderApiCall}); + return; + } + + callback.result_cb( + service_controller_->RejectConnection(client, endpoint_id)); + }); } -template -void ServiceControllerRouter::sendPayload( - Ptr > client_proxy, - ConstPtr send_payload_params) { - routeToServiceController( - MakePtr(new service_controller_router::SendPayloadRunnable( - self_, client_proxy, send_payload_params))); +void ServiceControllerRouter::InitiateBandwidthUpgrade( + ClientProxy* client, absl::string_view endpoint_id, + const ResultCallback& callback) { + RouteToServiceController( + [this, client, endpoint_id = std::string(endpoint_id), callback]() { + if (!ClientHasAcquiredServiceController(client) || + !client->IsConnectedToEndpoint(endpoint_id)) { + callback.result_cb({Status::kOutOfOrderApiCall}); + return; + } + + service_controller_->InitiateBandwidthUpgrade(client, endpoint_id); + + // Operation is triggered; the caller can listen to + // ConnectionListener::OnBandwidthChanged() to determine its success. + callback.result_cb({Status::kSuccess}); + }); } -template -void ServiceControllerRouter::cancelPayload( - Ptr > client_proxy, - ConstPtr cancel_payload_params) { - routeToServiceController( - MakePtr(new service_controller_router::CancelPayloadRunnable( - self_, client_proxy, cancel_payload_params))); +void ServiceControllerRouter::SendPayload( + ClientProxy* client, absl::Span endpoint_ids, + Payload payload, const ResultCallback& callback) { + // Payload is a move-only type. + // We have to capture it by value inside the lambda, and pass it over to + // the executor as an std::function instance. + // Lambda must be copyable, in order ot satisfy std::function<> requirements. + // To make it so, we need Payload wrapped by a copyable wrapper. + // std::shared_ptr<> is used, because it is copyable. + auto shared_payload = std::make_shared(std::move(payload)); + const std::vector endpoints = + std::vector(endpoint_ids.begin(), endpoint_ids.end()); + + RouteToServiceController( + [this, client, shared_payload, endpoints, callback]() { + if (!ClientHasAcquiredServiceController(client)) { + callback.result_cb({Status::kOutOfOrderApiCall}); + return; + } + + if (!ClientHasConnectionToAtLeastOneEndpoint(client, endpoints)) { + callback.result_cb({Status::kEndpointUnknown}); + return; + } + + service_controller_->SendPayload(client, endpoints, + std::move(*shared_payload)); + + // At this point, we've queued up the send Payload request with the + // ServiceController; any further failures (e.g. one of the endpoints is + // unknown, goes away, or otherwise fails) will be returned to the + // client as a PayloadTransferUpdate. + callback.result_cb({Status::kSuccess}); + }); } -template -void ServiceControllerRouter::disconnectFromEndpoint( - Ptr > client_proxy, - ConstPtr disconnect_from_endpoint_params) { - routeToServiceController(MakePtr( - new service_controller_router::DisconnectFromEndpointRunnable( - self_, client_proxy, disconnect_from_endpoint_params))); +void ServiceControllerRouter::CancelPayload(ClientProxy* client, + std::uint64_t payload_id, + const ResultCallback& callback) { + RouteToServiceController([this, client, payload_id, callback]() { + if (!ClientHasAcquiredServiceController(client)) { + callback.result_cb({Status::kOutOfOrderApiCall}); + return; + } + + callback.result_cb(service_controller_->CancelPayload(client, payload_id)); + }); } -template -void ServiceControllerRouter::stopAllEndpoints( - Ptr > client_proxy, - ConstPtr stop_all_endpoint_params) { - routeToServiceController( - MakePtr(new service_controller_router::StopAllEndpointsRunnable( - self_, client_proxy, stop_all_endpoint_params))); +void ServiceControllerRouter::DisconnectFromEndpoint( + ClientProxy* client, absl::string_view endpoint_id, + const ResultCallback& callback) { + RouteToServiceController( + [this, client, endpoint_id = std::string(endpoint_id), callback]() { + if (ClientHasAcquiredServiceController(client)) { + if (!client->IsConnectedToEndpoint(endpoint_id) && + !client->HasPendingConnectionToEndpoint(endpoint_id)) { + callback.result_cb({Status::kOutOfOrderApiCall}); + return; + } + service_controller_->DisconnectFromEndpoint(client, endpoint_id); + callback.result_cb({Status::kSuccess}); + } + }); } -template -void ServiceControllerRouter::clientDisconnecting( - Ptr> client_proxy) { - routeToServiceController(MakePtr( - new service_controller_router::ClientDisconnectingRunnable( - self_, client_proxy))); +void ServiceControllerRouter::StopAllEndpoints(ClientProxy* client, + const ResultCallback& callback) { + RouteToServiceController([this, client, callback]() { + if (ClientHasAcquiredServiceController(client)) { + DoneWithStrategySessionForClient(client); + } + callback.result_cb({Status::kSuccess}); + }); } -template -Status::Value -ServiceControllerRouter::acquireServiceControllerForClient( - Ptr > client_proxy, const Strategy& strategy) { - if (current_strategy_.isNull()) { +void ServiceControllerRouter::ClientDisconnecting( + ClientProxy* client, const ResultCallback& callback) { + RouteToServiceController([this, client, callback]() { + if (ClientHasAcquiredServiceController(client)) { + DoneWithStrategySessionForClient(client); + NEARBY_LOG(INFO, + "[ServiceControllerRouter:Disconnect]: Client has completed " + "the client's connection"); + } + callback.result_cb({Status::kSuccess}); + }); +} + +Status ServiceControllerRouter::AcquireServiceControllerForClient( + ClientProxy* client, Strategy strategy) { + if (current_strategy_.IsNone()) { // Case 1: There is no existing Strategy at all. // Set everything up for the first time. - Status::Value status = updateCurrentServiceControllerAndStrategy(strategy); - if (status != Status::SUCCESS) { + Status status = UpdateCurrentServiceControllerAndStrategy(strategy); + if (!status.Ok()) { return status; } - current_service_controller_clients_.insert(client_proxy); - return Status::SUCCESS; - } else if (strategy == *current_strategy_) { + clients_.insert(client); + return {Status::kSuccess}; + } else if (strategy == current_strategy_) { // Case 2: The existing Strategy matches. // The new client just needs to be added to the set of clients using the // current ServiceController. - current_service_controller_clients_.insert(client_proxy); - return Status::SUCCESS; + clients_.insert(client); + return {Status::kSuccess}; } else { // Case 3: The existing Strategy doesn't match. // It's only safe for a client to cause a switch if it's the only client // using the current ServiceController. bool is_the_only_client_of_service_controller = - current_service_controller_clients_.size() == 1 && - current_service_controller_clients_.find(client_proxy) != - current_service_controller_clients_.end(); + clients_.size() == 1 && ClientHasAcquiredServiceController(client); if (!is_the_only_client_of_service_controller) { - // TODO(tracyzhou): logging - return Status::ALREADY_HAVE_ACTIVE_STRATEGY; + NEARBY_LOG(INFO, + "[ServiceControllerRouter:AcquireServiceControllerForClient]: " + "Client has already active strategy."); + return {Status::kAlreadyHaveActiveStrategy}; } // If the client still has connected endpoints, they must disconnect before // they can switch. - if (!client_proxy->getConnectedEndpoints().empty()) { - // TODO(tracyzhou): logging - return Status::OUT_OF_ORDER_API_CALL; + if (!client->GetConnectedEndpoints().empty()) { + NEARBY_LOG(INFO, + "[ServiceControllerRouter:AcquireServiceControllerForClient]: " + "Client has connected endpoints."); + return {Status::kOutOfOrderApiCall}; } // By this point, it's safe to switch the Strategy and ServiceController // (and since it's the only client, there's no need to add it to the set of // clients using the current ServiceController). - return updateCurrentServiceControllerAndStrategy(strategy); + return UpdateCurrentServiceControllerAndStrategy(strategy); } } -template -bool ServiceControllerRouter::clientHasAquiredServiceController( - Ptr > client_proxy) { - return (current_service_controller_clients_.find(client_proxy) != - current_service_controller_clients_.end()); +bool ServiceControllerRouter::ClientHasAcquiredServiceController( + ClientProxy* client) const { + return clients_.contains(client); } -template -void ServiceControllerRouter::releaseServiceControllerForClient( - Ptr > client_proxy) { - current_service_controller_clients_.erase(client_proxy); +void ServiceControllerRouter::ReleaseServiceControllerForClient( + ClientProxy* client) { + clients_.erase(client); - if (current_service_controller_clients_.empty()) { - current_service_controller_.destroy(); - current_strategy_.destroy(); + if (clients_.empty()) { + service_controller_.reset(); + current_strategy_ = Strategy{}; } } /** Clean up all state for this client. The client is now free to switch * strategies. */ -template -void ServiceControllerRouter::doneWithStrategySessionForClient( - Ptr > client_proxy) { +void ServiceControllerRouter::DoneWithStrategySessionForClient( + ClientProxy* client) { // Disconnect from all the connected endpoints tied to this clientProxy. - std::vector pending_connected_endpoints = - client_proxy->getPendingConnectedEndpoints(); - - for (std::vector::iterator it = pending_connected_endpoints.begin(); - it != pending_connected_endpoints.end(); it++) { - current_service_controller_->disconnectFromEndpoint(client_proxy, *it); + for (auto& endpoint_id : client->GetPendingConnectedEndpoints()) { + service_controller_->DisconnectFromEndpoint(client, endpoint_id); } - std::vector connected_endpoints = - client_proxy->getConnectedEndpoints(); - - for (std::vector::iterator it = connected_endpoints.begin(); - it != connected_endpoints.end(); it++) { - current_service_controller_->disconnectFromEndpoint(client_proxy, *it); + for (auto& endpoint_id : client->GetConnectedEndpoints()) { + service_controller_->DisconnectFromEndpoint(client, endpoint_id); } // Stop any advertising and discovery that may be underway due to this // clientProxy. - current_service_controller_->stopAdvertising(client_proxy); - current_service_controller_->stopDiscovery(client_proxy); + service_controller_->StopAdvertising(client); + service_controller_->StopDiscovery(client); - // Finally, clear all state maintained by this clientProxy. - client_proxy->reset(); - - releaseServiceControllerForClient(client_proxy); + ReleaseServiceControllerForClient(client); } -template -void ServiceControllerRouter::routeToServiceController( - Ptr runnable) { - serializer_->execute(runnable); +void ServiceControllerRouter::RouteToServiceController(Runnable runnable) { + serializer_.Execute(std::move(runnable)); } -template -bool ServiceControllerRouter::clientHasConnectionToAtLeastOneEndpoint( - Ptr > client_proxy, - const std::vector& remote_endpoint_ids) { - for (std::vector::const_iterator it = remote_endpoint_ids.begin(); - it != remote_endpoint_ids.end(); it++) { - if (client_proxy->isConnectedToEndpoint(*it)) { +bool ServiceControllerRouter::ClientHasConnectionToAtLeastOneEndpoint( + ClientProxy* client, const std::vector& remote_endpoint_ids) { + for (auto& endpoint_id : remote_endpoint_ids) { + if (client->IsConnectedToEndpoint(endpoint_id)) { return true; } } return false; } -template -Status::Value -ServiceControllerRouter::updateCurrentServiceControllerAndStrategy( - const Strategy& strategy) { - if (!strategy.isValid()) { - // TODO(tracyzhou): logging - return Status::ERROR; +Status ServiceControllerRouter::UpdateCurrentServiceControllerAndStrategy( + Strategy strategy) { + if (!strategy.IsValid()) { + NEARBY_LOG(INFO, "Strategy is not valid."); + return {Status::kError}; } - current_service_controller_.destroy(); - current_service_controller_ = - MakePtr(new OfflineServiceController()); - current_strategy_.destroy(); - current_strategy_ = MakePtr(new Strategy(strategy)); + service_controller_.reset(service_controller_factory_()); + current_strategy_ = strategy; - return Status::SUCCESS; + return {Status::kSuccess}; } } // namespace connections diff --git a/cpp/core/internal/service_controller_router.h b/cpp/core/internal/service_controller_router.h index 73e2784c..26eb7bf2 100644 --- a/cpp/core/internal/service_controller_router.h +++ b/cpp/core/internal/service_controller_router.h @@ -1,152 +1,117 @@ #ifndef CORE_INTERNAL_SERVICE_CONTROLLER_ROUTER_H_ #define CORE_INTERNAL_SERVICE_CONTROLLER_ROUTER_H_ -#include +#include +#include #include #include "core/internal/client_proxy.h" #include "core/internal/service_controller.h" +#include "core/options.h" #include "core/params.h" -#include "platform/port/string.h" -#include "platform/ptr.h" -#include "platform/runnable.h" +#include "platform/base/runnable.h" +#include "platform/public/single_thread_executor.h" +#include "absl/container/flat_hash_set.h" +#include "absl/strings/string_view.h" +#include "absl/types/span.h" namespace location { namespace nearby { namespace connections { -namespace service_controller_router { - -template -class StartAdvertisingRunnable; -template -class StopAdvertisingRunnable; -template -class StartDiscoveryRunnable; -template -class StopDiscoveryRunnable; -template -class SendConnectionRequestRunnable; -template -class AcceptConnectionRequestRunnable; -template -class RejectConnectionRequestRunnable; -template -class InitiateBandwidthUpgradeRunnable; -template -class SendPayloadRunnable; -template -class CancelPayloadRunnable; -template -class DisconnectFromEndpointRunnable; -template -class StopAllEndpointsRunnable; -template -class ClientDisconnectingRunnable; - -} // namespace service_controller_router - -template +// ServiceControllerRouter: this class is an implementation detail of a +// location::nearby::Core class. The latter delegates all of its activities to +// the former. +// +// All the activities are documented in the public API class: +// https://source.corp.google.com/piper///depot/google3/core_v2/core.h +// +// In every method, ClientProxy* represents the client app which receives +// notifications from Nearby Connections service and forwards them to the app. +// The rest of arguments have the same meaning as the corresponding +// methods in the definition of location::nearby::Core API. +// +// Every activity is handled the same way: +// 1) all the arguments to the call are captured by value; +// 2) the actual processing is scheduled on a private single-threaded executor, +// which makes locking unnecessary, when internal data is being manipulated. +// 3) activity handlers are delegating much of their work to an implementation +// of a ServiceController interface, which does the actual job. class ServiceControllerRouter { public: - ServiceControllerRouter(); + explicit ServiceControllerRouter(std::function factory) + : service_controller_factory_(std::move(factory)) {} ~ServiceControllerRouter(); + ServiceControllerRouter(ServiceControllerRouter&&) = default; + ServiceControllerRouter& operator=(ServiceControllerRouter&&) = default; - void startAdvertising( - Ptr > client_proxy, - ConstPtr start_advertising_params); - void stopAdvertising(Ptr > client_proxy, - ConstPtr stop_advertising_params); + void StartAdvertising(ClientProxy* client, absl::string_view service_id, + const ConnectionOptions& options, + const ConnectionRequestInfo& info, + const ResultCallback& callback); + void StopAdvertising(ClientProxy* client, const ResultCallback& callback); - void startDiscovery(Ptr > client_proxy, - ConstPtr start_discovery_params); - void stopDiscovery(Ptr > client_proxy, - ConstPtr stop_discovery_params); + void StartDiscovery(ClientProxy* client, absl::string_view service_id, + const ConnectionOptions& options, + const DiscoveryListener& listener, + const ResultCallback& callback); + void StopDiscovery(ClientProxy* client, const ResultCallback& callback); - void requestConnection( - Ptr > client_proxy, - ConstPtr request_connection_params); - void acceptConnection( - Ptr > client_proxy, - ConstPtr accept_connection_params); - void rejectConnection( - Ptr > client_proxy, - ConstPtr reject_connection_params); + void InjectEndpoint(ClientProxy* client, + absl::string_view service_id, + const OutOfBandConnectionMetadata& metadata, + const ResultCallback& callback); - void initiateBandwidthUpgrade(Ptr > client_proxy, - ConstPtr - initiate_bandwidth_upgrade_params); + void RequestConnection(ClientProxy* client, absl::string_view endpoint_id, + const ConnectionRequestInfo& info, + const ConnectionOptions& options, + const ResultCallback& callback); + void AcceptConnection(ClientProxy* client, absl::string_view endpoint_id, + const PayloadListener& listener, + const ResultCallback& callback); + void RejectConnection(ClientProxy* client, absl::string_view endpoint_id, + const ResultCallback& callback); - void sendPayload(Ptr > client_proxy, - ConstPtr send_payload_params); - void cancelPayload(Ptr > client_proxy, - ConstPtr cancel_payload_params); + void InitiateBandwidthUpgrade(ClientProxy* client, + absl::string_view endpoint_id, + const ResultCallback& callback); - void disconnectFromEndpoint( - Ptr > client_proxy, - ConstPtr disconnect_from_endpoint_params); - void stopAllEndpoints( - Ptr > client_proxy, - ConstPtr stop_all_endpoint_params); + void SendPayload(ClientProxy* client, + absl::Span endpoint_ids, Payload payload, + const ResultCallback& callback); + void CancelPayload(ClientProxy* client, std::uint64_t payload_id, + const ResultCallback& callback); - void clientDisconnecting(Ptr > client_proxy); + void DisconnectFromEndpoint(ClientProxy* client, + absl::string_view endpoint_id, + const ResultCallback& callback); + void StopAllEndpoints(ClientProxy* client, const ResultCallback& callback); + + void ClientDisconnecting(ClientProxy* client, const ResultCallback& callback); private: - template - friend class service_controller_router::StartAdvertisingRunnable; - template - friend class service_controller_router::StopAdvertisingRunnable; - template - friend class service_controller_router::StartDiscoveryRunnable; - template - friend class service_controller_router::StopDiscoveryRunnable; - template - friend class service_controller_router::SendConnectionRequestRunnable; - template - friend class service_controller_router::AcceptConnectionRequestRunnable; - template - friend class service_controller_router::RejectConnectionRequestRunnable; - template - friend class service_controller_router::InitiateBandwidthUpgradeRunnable; - template - friend class service_controller_router::SendPayloadRunnable; - template - friend class service_controller_router::CancelPayloadRunnable; - template - friend class service_controller_router::DisconnectFromEndpointRunnable; - template - friend class service_controller_router::StopAllEndpointsRunnable; - template - friend class service_controller_router::ClientDisconnectingRunnable; + friend class ServiceControllerRouterTest; + static bool ClientHasConnectionToAtLeastOneEndpoint( + ClientProxy* client, const std::vector& remote_endpoint_ids); - static bool clientHasConnectionToAtLeastOneEndpoint( - Ptr > client_proxy, - const std::vector& remote_endpoint_ids); + void RouteToServiceController(Runnable runnable); - void routeToServiceController(Ptr runnable); + Status AcquireServiceControllerForClient(ClientProxy* client, + Strategy strategy); + bool ClientHasAcquiredServiceController(ClientProxy* client) const; + void ReleaseServiceControllerForClient(ClientProxy* client); + void DoneWithStrategySessionForClient(ClientProxy* client); + Status UpdateCurrentServiceControllerAndStrategy(Strategy strategy); - Status::Value acquireServiceControllerForClient( - Ptr > client_proxy, const Strategy& strategy); - bool clientHasAquiredServiceController( - Ptr > client_proxy); - void releaseServiceControllerForClient( - Ptr > client_proxy); - void doneWithStrategySessionForClient( - Ptr > client_proxy); - Status::Value updateCurrentServiceControllerAndStrategy( - const Strategy& strategy); - - std::set > > current_service_controller_clients_; - Ptr > current_service_controller_; - Ptr current_strategy_; - ScopedPtr > serializer_; - std::shared_ptr> self_{this, [](void*){}}; + absl::flat_hash_set clients_; + std::function service_controller_factory_; + std::unique_ptr service_controller_; + Strategy current_strategy_; + SingleThreadExecutor serializer_; }; } // namespace connections } // namespace nearby } // namespace location -#include "core/internal/service_controller_router.cc" - #endif // CORE_INTERNAL_SERVICE_CONTROLLER_ROUTER_H_ diff --git a/cpp/core_v2/internal/service_controller_router_test.cc b/cpp/core/internal/service_controller_router_test.cc similarity index 90% rename from cpp/core_v2/internal/service_controller_router_test.cc rename to cpp/core/internal/service_controller_router_test.cc index 0f34225d..aa4a8c62 100644 --- a/cpp/core_v2/internal/service_controller_router_test.cc +++ b/cpp/core/internal/service_controller_router_test.cc @@ -1,19 +1,20 @@ -#include "core_v2/internal/service_controller_router.h" +#include "core/internal/service_controller_router.h" +#include #include #include #include -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/mock_service_controller.h" -#include "core_v2/internal/service_controller.h" -#include "core_v2/listeners.h" -#include "core_v2/options.h" -#include "core_v2/params.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/public/condition_variable.h" -#include "platform_v2/public/mutex.h" -#include "platform_v2/public/mutex_lock.h" +#include "core/internal/client_proxy.h" +#include "core/internal/mock_service_controller.h" +#include "core/internal/service_controller.h" +#include "core/listeners.h" +#include "core/options.h" +#include "core/params.h" +#include "platform/base/byte_array.h" +#include "platform/public/condition_variable.h" +#include "platform/public/mutex.h" +#include "platform/public/mutex_lock.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/container/flat_hash_set.h" @@ -26,6 +27,7 @@ namespace connections { namespace { using ::testing::Return; +constexpr std::array kFakeMacAddress = {'a', 'b', 'c', 'd', 'e', 'f'}; } // namespace // This class must be in the same namespace as ServiceControllerRouter for @@ -96,6 +98,18 @@ class ServiceControllerRouterTest : public testing::Test { EXPECT_FALSE(client->IsDiscovering()); } + void InjectEndpoint(ClientProxy* client, std::string service_id, + const OutOfBandConnectionMetadata& metadata, + ResultCallback callback) { + EXPECT_CALL(mock_, InjectEndpoint).Times(1); + { + MutexLock lock(&mutex_); + complete_ = false; + router_.InjectEndpoint(client, service_id, metadata, callback); + while (!complete_) cond_.Wait(); + } + } + void RequestConnection(ClientProxy* client, const std::string& endpoint_id, const ConnectionRequestInfo& request_info, ResultCallback callback) { @@ -240,6 +254,10 @@ class ServiceControllerRouterTest : public testing::Test { .auto_upgrade_bandwidth = true, .enforce_topology_constraints = true, }; + const OutOfBandConnectionMetadata kOutOfBandConnectionMetadata{ + .medium = Medium::BLUETOOTH, + .remote_bluetooth_mac_address = ByteArray(kFakeMacAddress), + }; std::vector mediums_{ proto::connections::Medium::BLUETOOTH}; @@ -287,6 +305,13 @@ TEST_F(ServiceControllerRouterTest, StopDiscoveryCalled) { StopDiscovery(&client_, kCallback); } +TEST_F(ServiceControllerRouterTest, InjectEndpointCalled) { + StartDiscovery(&client_, kServiceId, kConnectionOptions, discovery_listener_, + kCallback); + InjectEndpoint(&client_, kServiceId, kOutOfBandConnectionMetadata, kCallback); + StopDiscovery(&client_, kCallback); +} + TEST_F(ServiceControllerRouterTest, RequestConnectionCalled) { // Either Advertising, or Discovery should be ongoing. StartDiscovery(&client_, kServiceId, kConnectionOptions, discovery_listener_, diff --git a/cpp/core_v2/internal/simulation_user.cc b/cpp/core/internal/simulation_user.cc similarity index 94% rename from cpp/core_v2/internal/simulation_user.cc rename to cpp/core/internal/simulation_user.cc index 7c38f5e5..261300c4 100644 --- a/cpp/core_v2/internal/simulation_user.cc +++ b/cpp/core/internal/simulation_user.cc @@ -1,8 +1,8 @@ -#include "core_v2/internal/simulation_user.h" +#include "core/internal/simulation_user.h" -#include "core_v2/listeners.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/system_clock.h" +#include "core/listeners.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/system_clock.h" #include "absl/functional/bind_front.h" namespace location { @@ -117,6 +117,12 @@ void SimulationUser::StartDiscovery(const std::string& service_id, .Ok()); } +void SimulationUser::InjectEndpoint( + const std::string& service_id, + const OutOfBandConnectionMetadata& metadata) { + mgr_.InjectEndpoint(&client_, service_id, metadata); +} + void SimulationUser::RequestConnection(CountDownLatch* latch) { initiated_latch_ = latch; ConnectionListener listener = { diff --git a/cpp/core_v2/internal/simulation_user.h b/cpp/core/internal/simulation_user.h similarity index 85% rename from cpp/core_v2/internal/simulation_user.h rename to cpp/core/internal/simulation_user.h index 2b48353c..1f04789e 100644 --- a/cpp/core_v2/internal/simulation_user.h +++ b/cpp/core/internal/simulation_user.h @@ -1,19 +1,19 @@ -#ifndef CORE_V2_INTERNAL_SIMULATION_USER_H_ -#define CORE_V2_INTERNAL_SIMULATION_USER_H_ +#ifndef CORE_INTERNAL_SIMULATION_USER_H_ +#define CORE_INTERNAL_SIMULATION_USER_H_ #include -#include "core_v2/internal/bwu_manager.h" -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/endpoint_channel_manager.h" -#include "core_v2/internal/endpoint_manager.h" -#include "core_v2/internal/payload_manager.h" -#include "core_v2/internal/pcp_manager.h" -#include "core_v2/options.h" -#include "platform_v2/base/medium_environment.h" -#include "platform_v2/public/condition_variable.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/future.h" +#include "core/internal/bwu_manager.h" +#include "core/internal/client_proxy.h" +#include "core/internal/endpoint_channel_manager.h" +#include "core/internal/endpoint_manager.h" +#include "core/internal/payload_manager.h" +#include "core/internal/pcp_manager.h" +#include "core/options.h" +#include "platform/base/medium_environment.h" +#include "platform/public/condition_variable.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/future.h" #include "gtest/gtest.h" // Test-only class to help run end-to-end simulations for nearby connections @@ -60,6 +60,10 @@ class SimulationUser { // callback. void StartDiscovery(const std::string& service_id, CountDownLatch* latch); + // 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. @@ -140,4 +144,4 @@ class SimulationUser { } // namespace nearby } // namespace location -#endif // CORE_V2_INTERNAL_SIMULATION_USER_H_ +#endif // CORE_INTERNAL_SIMULATION_USER_H_ diff --git a/cpp/core_v2/internal/webrtc_bwu_handler.cc b/cpp/core/internal/webrtc_bwu_handler.cc similarity index 75% rename from cpp/core_v2/internal/webrtc_bwu_handler.cc rename to cpp/core/internal/webrtc_bwu_handler.cc index c55e7bad..22eef4d6 100644 --- a/cpp/core_v2/internal/webrtc_bwu_handler.cc +++ b/cpp/core/internal/webrtc_bwu_handler.cc @@ -1,12 +1,13 @@ -#include "core_v2/internal/webrtc_bwu_handler.h" +#include "core/internal/webrtc_bwu_handler.h" +#include #include -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/mediums/utils.h" -#include "core_v2/internal/mediums/webrtc/peer_id.h" -#include "core_v2/internal/offline_frames.h" -#include "core_v2/internal/webrtc_endpoint_channel.h" +#include "core/internal/client_proxy.h" +#include "core/internal/mediums/utils.h" +#include "core/internal/mediums/webrtc/peer_id.h" +#include "core/internal/offline_frames.h" +#include "core/internal/webrtc_endpoint_channel.h" #include "absl/functional/bind_front.h" // Manages the Bluetooth-specific methods needed to upgrade an {@link @@ -60,14 +61,17 @@ ByteArray WebrtcBwuHandler::InitializeUpgradedMediumForEndpoint( // stop the advertising yet. std::string upgrade_service_id = Utils::WrapUpgradeServiceId(service_id); + LocationHint location_hint = Utils::BuildLocationHint(GetCountryCode()); + mediums::PeerId self_id{mediums::PeerId::FromRandom()}; if (!webrtc_.IsAcceptingConnections()) { if (!webrtc_.StartAcceptingConnections( - self_id, { - .accepted_cb = absl::bind_front( - &WebrtcBwuHandler::OnIncomingWebrtcConnection, - this, client, upgrade_service_id), - })) { + self_id, location_hint, + { + .accepted_cb = absl::bind_front( + &WebrtcBwuHandler::OnIncomingWebrtcConnection, this, client, + upgrade_service_id), + })) { NEARBY_LOG(ERROR, "WebRtcBwuHandler couldn't initiate the WEB_RTC upgrade for " "endpoint %s because it failed to start listening for " @@ -84,7 +88,7 @@ ByteArray WebrtcBwuHandler::InitializeUpgradedMediumForEndpoint( // cache service ID to revert active_service_ids_.emplace(upgrade_service_id); - return parser::ForBwuWebrtcPathAvailable(self_id.GetId()); + return parser::ForBwuWebrtcPathAvailable(self_id.GetId(), location_hint); } // Called by BWU target. Retrieves a new medium info from incoming message, @@ -97,11 +101,17 @@ WebrtcBwuHandler::CreateUpgradedEndpointChannel( upgrade_path_info.web_rtc_credentials(); mediums::PeerId peer_id(web_rtc_credentials.peer_id()); + LocationHint location_hint; + location_hint.set_format(LocationStandard::UNKNOWN); + if (web_rtc_credentials.has_location_hint()) { + location_hint = web_rtc_credentials.location_hint(); + } NEARBY_LOG(INFO, - "WebRtcBwuHandler is attempting to connect to remote peer %s", - peer_id.GetId().c_str()); + "WebRtcBwuHandler is attempting to connect to remote peer %s, " + "location hint %s", + peer_id.GetId().c_str(), location_hint.DebugString().c_str()); - mediums::WebRtcSocketWrapper socket = webrtc_.Connect(peer_id); + mediums::WebRtcSocketWrapper socket = webrtc_.Connect(peer_id, location_hint); if (!socket.IsValid()) { NEARBY_LOG(ERROR, "WebRtcBwuHandler failed to connect to remote peer (%s) on " @@ -131,6 +141,23 @@ WebrtcBwuHandler::CreateUpgradedEndpointChannel( void WebrtcBwuHandler::OnEndpointDisconnect(ClientProxy* client, const std::string& endpoint_id) {} +std::string WebrtcBwuHandler::GetCountryCode() { + std::string default_locale_name = std::locale("").name(); + + // locale name has a format: _. + int s = default_locale_name.find("_"); + int e = default_locale_name.find("."); + + if (s == -1 || e == -1) { + return ""; + } + + auto country_code = default_locale_name.substr(s + 1, e - s - 1); + std::transform(country_code.begin(), country_code.end(), country_code.begin(), + std::towlower); + return country_code; +} + WebrtcBwuHandler::WebrtcIncomingSocket::WebrtcIncomingSocket( const std::string& name, mediums::WebRtcSocketWrapper socket) : name_(name), socket_(socket) {} diff --git a/cpp/core_v2/internal/webrtc_bwu_handler.h b/cpp/core/internal/webrtc_bwu_handler.h similarity index 86% rename from cpp/core_v2/internal/webrtc_bwu_handler.h rename to cpp/core/internal/webrtc_bwu_handler.h index 793357d8..ca0c3cb2 100644 --- a/cpp/core_v2/internal/webrtc_bwu_handler.h +++ b/cpp/core/internal/webrtc_bwu_handler.h @@ -1,11 +1,11 @@ -#ifndef CORE_V2_INTERNAL_WEBRTC_BWU_HANDLER_H_ -#define CORE_V2_INTERNAL_WEBRTC_BWU_HANDLER_H_ +#ifndef CORE_INTERNAL_WEBRTC_BWU_HANDLER_H_ +#define CORE_INTERNAL_WEBRTC_BWU_HANDLER_H_ -#include "core_v2/internal/base_bwu_handler.h" -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/endpoint_channel_manager.h" -#include "core_v2/internal/mediums/mediums.h" -#include "core_v2/internal/mediums/webrtc/webrtc_socket_wrapper.h" +#include "core/internal/base_bwu_handler.h" +#include "core/internal/client_proxy.h" +#include "core/internal/endpoint_channel_manager.h" +#include "core/internal/mediums/mediums.h" +#include "core/internal/mediums/webrtc/webrtc_socket_wrapper.h" namespace location { namespace nearby { @@ -53,6 +53,8 @@ class WebrtcBwuHandler : public BaseBwuHandler { void OnEndpointDisconnect(ClientProxy* client, const std::string& endpoint_id) override; + std::string GetCountryCode(); + class WebrtcIncomingSocket : public BwuHandler::IncomingSocket { public: explicit WebrtcIncomingSocket(const std::string& name, @@ -76,4 +78,4 @@ class WebrtcBwuHandler : public BaseBwuHandler { } // namespace nearby } // namespace location -#endif // CORE_V2_INTERNAL_WEBRTC_BWU_HANDLER_H_ +#endif // CORE_INTERNAL_WEBRTC_BWU_HANDLER_H_ diff --git a/cpp/core_v2/internal/webrtc_endpoint_channel.cc b/cpp/core/internal/webrtc_endpoint_channel.cc similarity index 91% rename from cpp/core_v2/internal/webrtc_endpoint_channel.cc rename to cpp/core/internal/webrtc_endpoint_channel.cc index 0c22add5..7df735ee 100644 --- a/cpp/core_v2/internal/webrtc_endpoint_channel.cc +++ b/cpp/core/internal/webrtc_endpoint_channel.cc @@ -1,4 +1,4 @@ -#include "core_v2/internal/webrtc_endpoint_channel.h" +#include "core/internal/webrtc_endpoint_channel.h" namespace location { namespace nearby { diff --git a/cpp/core_v2/internal/webrtc_endpoint_channel.h b/cpp/core/internal/webrtc_endpoint_channel.h similarity index 65% rename from cpp/core_v2/internal/webrtc_endpoint_channel.h rename to cpp/core/internal/webrtc_endpoint_channel.h index dc5b8512..6dfe2221 100644 --- a/cpp/core_v2/internal/webrtc_endpoint_channel.h +++ b/cpp/core/internal/webrtc_endpoint_channel.h @@ -1,8 +1,8 @@ -#ifndef CORE_V2_INTERNAL_WEBRTC_ENDPOINT_CHANNEL_H_ -#define CORE_V2_INTERNAL_WEBRTC_ENDPOINT_CHANNEL_H_ +#ifndef CORE_INTERNAL_WEBRTC_ENDPOINT_CHANNEL_H_ +#define CORE_INTERNAL_WEBRTC_ENDPOINT_CHANNEL_H_ -#include "core_v2/internal/base_endpoint_channel.h" -#include "core_v2/internal/mediums/webrtc/webrtc_socket_wrapper.h" +#include "core/internal/base_endpoint_channel.h" +#include "core/internal/mediums/webrtc/webrtc_socket_wrapper.h" #include "proto/connections_enums.pb.h" namespace location { @@ -26,4 +26,4 @@ class WebRtcEndpointChannel final : public BaseEndpointChannel { } // namespace nearby } // namespace location -#endif // CORE_V2_INTERNAL_WEBRTC_ENDPOINT_CHANNEL_H_ +#endif // CORE_INTERNAL_WEBRTC_ENDPOINT_CHANNEL_H_ diff --git a/cpp/core/internal/wifi_lan_endpoint_channel.cc b/cpp/core/internal/wifi_lan_endpoint_channel.cc index ca2589a5..007fe378 100644 --- a/cpp/core/internal/wifi_lan_endpoint_channel.cc +++ b/cpp/core/internal/wifi_lan_endpoint_channel.cc @@ -2,45 +2,44 @@ #include +#include "platform/public/logging.h" +#include "platform/public/wifi_lan.h" + namespace location { namespace nearby { namespace connections { -Ptr -WifiLanEndpointChannel::CreateOutgoing( - Ptr> medium_manager, - absl::string_view channel_name, Ptr wifi_lan_socket) { - return MakePtr( - new WifiLanEndpointChannel(channel_name, wifi_lan_socket)); +namespace { + +OutputStream* GetOutputStreamOrNull(WifiLanSocket& socket) { + if (socket.GetRemoteWifiLanService().IsValid()) + return &socket.GetOutputStream(); + return nullptr; } -Ptr -WifiLanEndpointChannel::CreateIncoming( - Ptr> medium_manager, - absl::string_view channel_name, Ptr wifi_lan_socket) { - return MakePtr( - new WifiLanEndpointChannel(channel_name, wifi_lan_socket)); +InputStream* GetInputStreamOrNull(WifiLanSocket& socket) { + if (socket.GetRemoteWifiLanService().IsValid()) + return &socket.GetInputStream(); + return nullptr; } -WifiLanEndpointChannel::WifiLanEndpointChannel( - absl::string_view channel_name, Ptr wifi_lan_socket) - : BaseEndpointChannel(channel_name, - wifi_lan_socket->GetInputStream(), - wifi_lan_socket->GetOutputStream()), - wifi_lan_socket_(wifi_lan_socket) {} +} // namespace -WifiLanEndpointChannel::~WifiLanEndpointChannel() {} +WifiLanEndpointChannel::WifiLanEndpointChannel(const std::string& channel_name, + WifiLanSocket socket) + : BaseEndpointChannel(channel_name, GetInputStreamOrNull(socket), + GetOutputStreamOrNull(socket)), + wifi_lan_socket_(std::move(socket)) {} -proto::connections::Medium WifiLanEndpointChannel::getMedium() { +proto::connections::Medium WifiLanEndpointChannel::GetMedium() const { return proto::connections::Medium::WIFI_LAN; } -void WifiLanEndpointChannel::closeImpl() { - Exception::Value exception = wifi_lan_socket_->Close(); - if (exception != Exception::NONE) { - if (exception == Exception::IO) { - // TODO(b/149806065): Add logging. - } +void WifiLanEndpointChannel::CloseImpl() { + auto status = wifi_lan_socket_.Close(); + if (!status.Ok()) { + NEARBY_LOG(INFO, "Failed to close WifiLan socket: exception=%d", + status.value); } } diff --git a/cpp/core/internal/wifi_lan_endpoint_channel.h b/cpp/core/internal/wifi_lan_endpoint_channel.h index 8d31df0f..9566bc0c 100644 --- a/cpp/core/internal/wifi_lan_endpoint_channel.h +++ b/cpp/core/internal/wifi_lan_endpoint_channel.h @@ -2,41 +2,25 @@ #define CORE_INTERNAL_WIFI_LAN_ENDPOINT_CHANNEL_H_ #include "core/internal/base_endpoint_channel.h" -#include "core/internal/medium_manager.h" -#include "platform/api/platform.h" -#include "platform/api/wifi_lan.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "platform/public/wifi_lan.h" #include "proto/connections_enums.pb.h" -#include "absl/strings/string_view.h" namespace location { namespace nearby { namespace connections { -class WifiLanEndpointChannel : public BaseEndpointChannel { +class WifiLanEndpointChannel final : public BaseEndpointChannel { public: - using Platform = platform::ImplementationPlatform; + // Creates both outgoing and incoming WifiLan channels. + WifiLanEndpointChannel(const std::string& channel_name, + WifiLanSocket socket); - static Ptr CreateOutgoing( - Ptr> medium_manager, - absl::string_view channel_name, Ptr wifi_lan_socket); - static Ptr CreateIncoming( - Ptr> medium_manager, - absl::string_view channel_name, Ptr wifi_lan_socket); - - ~WifiLanEndpointChannel() override; - - proto::connections::Medium getMedium() override; - - protected: - void closeImpl() override; + proto::connections::Medium GetMedium() const override; private: - WifiLanEndpointChannel(absl::string_view channel_name, - Ptr wifi_lan_socket); + void CloseImpl() override; - ScopedPtr > wifi_lan_socket_; + WifiLanSocket wifi_lan_socket_; }; } // namespace connections diff --git a/cpp/core/internal/wifi_lan_service_info.cc b/cpp/core/internal/wifi_lan_service_info.cc index 7cfb9b3e..7cda3436 100644 --- a/cpp/core/internal/wifi_lan_service_info.cc +++ b/cpp/core/internal/wifi_lan_service_info.cc @@ -1,201 +1,180 @@ #include "core/internal/wifi_lan_service_info.h" -#include +#include -#include "platform/base64_utils.h" +#include +#include + +#include "platform/base/base64_utils.h" +#include "platform/base/base_input_stream.h" +#include "platform/public/logging.h" +#include "absl/strings/str_cat.h" namespace location { namespace nearby { namespace connections { -Ptr WifiLanServiceInfo::FromString( - absl::string_view wifi_lan_service_info_string) { - ScopedPtr > scoped_wifi_lan_service_info_name_bytes( - Base64Utils::decode(wifi_lan_service_info_string)); - if (scoped_wifi_lan_service_info_name_bytes.isNull()) { - // TODO(b/149806065): logger.atDebug().log("Cannot deserialize - // WifiLanServiceInfo: failed Base64 decoding of %s", - // WifiLanServiceInfoString); - return Ptr(); +WifiLanServiceInfo::WifiLanServiceInfo(Version version, Pcp pcp, + absl::string_view endpoint_id, + const ByteArray& service_id_hash, + const ByteArray& endpoint_info, + const ByteArray& uwb_address, + WebRtcState web_rtc_state) { + if (version != Version::kV1 || endpoint_id.empty() || + endpoint_id.length() != kEndpointIdLength || + service_id_hash.size() != kServiceIdHashLength || + endpoint_info.size() > kMaxEndpointInfoLength) { + return; } - - if (scoped_wifi_lan_service_info_name_bytes->size() > - kMaxLanServiceNameLength) { - // TODO(b/149806065): logger.atDebug().log("Cannot deserialize - // WifiLanServiceInfo: expecting max %d raw bytes, got %d", - // MAX_WIFILAN_SERVICE_INFO_LENGTH, wifiLanServiceInfoNameBytes.length); - return Ptr(); - } - - if (scoped_wifi_lan_service_info_name_bytes->size() < - kMinLanServiceNameLength) { - // TODO(b/149806065): logger.atDebug().log("Cannot deserialize - // WifiLanServiceInfo: expecting min %d raw bytes, got %d", - // MIN_WIFILAN_SERVICE_INFO_LENGTH, wifiLanServiceInfoNameBytes.length); - return Ptr(); - } - - // The upper 3 bits are supposed to be the version. - Version version = static_cast( - (scoped_wifi_lan_service_info_name_bytes->getData()[0] & - kVersionBitmask) >> - kVersionShift); - - switch (version) { - case Version::kV1: - return CreateV1WifiLanServiceInfo( - ConstifyPtr(scoped_wifi_lan_service_info_name_bytes.get())); - - default: - // TODO(b/149806065): [ANALYTICIZE] This either represents corruption over - // the air, or older versions of GmsCore intermingling with newer ones. - - // TODO(b/149806065): logger.atDebug().log("Cannot deserialize - // WifiLanServiceInfo: unsupported Version %d", version); - return Ptr(); - } -} - -std::string WifiLanServiceInfo::AsString(Version version, PCP::Value pcp, - absl::string_view endpoint_id, - ConstPtr service_id_hash) { - Ptr wifi_lan_service_info_name_bytes; - switch (version) { - case Version::kV1: - wifi_lan_service_info_name_bytes = - CreateV1Bytes(pcp, endpoint_id, service_id_hash); - if (wifi_lan_service_info_name_bytes.isNull()) { - return ""; - } - break; - - default: - // TODO(b/149806065): logger.atDebug().log("Cannot serialize - // WifiLanServiceInfo: unsupported Version %d", version); - return ""; - } - ScopedPtr > scoped_wifi_lan_service_info_name_bytes( - wifi_lan_service_info_name_bytes); - - // WifiLanServiceInfo needs to be binary safe, so apply a Base64 encoding - // over the raw bytes. - return Base64Utils::encode( - ConstifyPtr(scoped_wifi_lan_service_info_name_bytes.get())); -} - -Ptr WifiLanServiceInfo::CreateV1WifiLanServiceInfo( - ConstPtr wifi_lan_service_info_name_bytes) { - const char* wifi_lan_service_info_name_bytes_read_ptr = - wifi_lan_service_info_name_bytes->getData(); - - // The lower 5 bits of the V1 payload are supposed to be the PCP. - PCP::Value pcp = static_cast( - *wifi_lan_service_info_name_bytes_read_ptr & kPcpBitmask); - wifi_lan_service_info_name_bytes_read_ptr++; - switch (pcp) { - case PCP::P2P_CLUSTER: // Fall through - case PCP::P2P_STAR: // Fall through - case PCP::P2P_POINT_TO_POINT: { - // The next 32 bits are supposed to be the endpoint_id. - std::string endpoint_id(wifi_lan_service_info_name_bytes_read_ptr, - kEndpointIdLength); - wifi_lan_service_info_name_bytes_read_ptr += kEndpointIdLength; - - // The next 24 bits are supposed to be the scoped_service_id_hash. - ScopedPtr > scoped_service_id_hash( - MakeConstPtr(new ByteArray(wifi_lan_service_info_name_bytes_read_ptr, - kServiceIdHashLength))); - wifi_lan_service_info_name_bytes_read_ptr += kServiceIdHashLength; - - // The next bits are supposed to be endpoint_name. - // TODO(b/149806065): Implements it. Temp to set "found_device". - std::string endpoint_name("found_device"); - - return MakePtr(new WifiLanServiceInfo(Version::kV1, pcp, endpoint_id, - scoped_service_id_hash.release(), - endpoint_name)); - } + case Pcp::kP2pCluster: // Fall through + case Pcp::kP2pStar: // Fall through + case Pcp::kP2pPointToPoint: + break; default: - // TODO(b/149806065): [ANALYTICIZE] This either represents corruption over - // the air, or older versions of GmsCore intermingling with newer ones. + return; + } - // TODO(b/149806065): logger.atDebug().log("Cannot deserialize - // WifiLanServiceInfo: unsupported V1 PCP %d", pcp); - return Ptr(); + version_ = version; + pcp_ = pcp; + service_id_hash_ = service_id_hash; + endpoint_id_ = std::string(endpoint_id); + endpoint_info_ = endpoint_info; + uwb_address_ = uwb_address; + web_rtc_state_ = web_rtc_state; +} + +WifiLanServiceInfo::WifiLanServiceInfo(absl::string_view service_info_name, + absl::string_view endpoint_info_name) { + ByteArray service_info_bytes = Base64Utils::Decode(service_info_name); + endpoint_info_ = Base64Utils::Decode(endpoint_info_name); + if (endpoint_info_.size() > kMaxEndpointInfoLength) { + NEARBY_LOG(INFO, + "Cannot deserialize EndpointInfo: expecting endpoint info " + "max %d raw bytes, got %" PRIu64, + kMaxEndpointInfoLength, endpoint_info_.size()); + return; + } + + if (service_info_bytes.Empty()) { + NEARBY_LOG( + INFO, + "Cannot deserialize WifiLanServiceInfo: failed Base64 decoding of %s", + std::string(service_info_name).c_str()); + return; + } + + if (service_info_bytes.size() < kMinLanServiceNameLength) { + NEARBY_LOG(INFO, + "Cannot deserialize WifiLanServiceInfo: expecting min %d raw " + "bytes, got %" PRIu64, + kMinLanServiceNameLength, service_info_bytes.size()); + return; + } + + BaseInputStream base_input_stream{service_info_bytes}; + // The first 1 byte is supposed to be the version and pcp. + auto version_and_pcp_byte = static_cast(base_input_stream.ReadUint8()); + // The upper 3 bits are supposed to be the version. + version_ = + static_cast((version_and_pcp_byte & kVersionBitmask) >> 5); + if (version_ != Version::kV1) { + NEARBY_LOG(INFO, + "Cannot deserialize WifiLanServiceInfo: unsupported Version %d", + version_); + return; + } + // The lower 5 bits are supposed to be the Pcp. + pcp_ = static_cast(version_and_pcp_byte & kPcpBitmask); + switch (pcp_) { + case Pcp::kP2pCluster: // Fall through + case Pcp::kP2pStar: // Fall through + case Pcp::kP2pPointToPoint: + break; + default: + NEARBY_LOG(INFO, + "Cannot deserialize WifiLanServiceInfo: unsupported V1 PCP %d", + pcp_); + } + + // The next 4 bytes are supposed to be the endpoint_id. + endpoint_id_ = std::string{base_input_stream.ReadBytes(kEndpointIdLength)}; + + // The next 3 bytes are supposed to be the service_id_hash. + service_id_hash_ = base_input_stream.ReadBytes(kServiceIdHashLength); + + // The next 1 byte is supposed to be the length of the uwb_address. If + // available, continues to deserialize UWB address and extra field of WebRtc + // state. + if (base_input_stream.IsAvailable(1)) { + std::uint32_t expected_uwb_address_length = base_input_stream.ReadUint8(); + // If the length of uwb_address is not zero, then retrieve it. + if (expected_uwb_address_length != 0) { + uwb_address_ = base_input_stream.ReadBytes(expected_uwb_address_length); + if (uwb_address_.Empty() || + uwb_address_.size() != expected_uwb_address_length) { + NEARBY_LOG(INFO, + "Cannot deserialize WifiLanServiceInfo: expected " + "uwbAddress size to be %d bytes, got %" PRIu64, + expected_uwb_address_length, uwb_address_.size()); + // Clear enpoint_id for validity. + endpoint_id_.clear(); + return; + } + } + + // The next 1 byte is extra field. + web_rtc_state_ = WebRtcState::kUndefined; + if (base_input_stream.IsAvailable(kExtraFieldLength)) { + auto extra_field = static_cast(base_input_stream.ReadUint8()); + web_rtc_state_ = (extra_field & kWebRtcConnectableFlagBitmask) == 1 + ? WebRtcState::kConnectable + : WebRtcState::kUnconnectable; + } } } -std::uint32_t WifiLanServiceInfo::ComputeEndpointNameLength( - ConstPtr wifi_lan_service_info_name_bytes) { - return kMaxEndpointNameLength - - (kMaxLanServiceNameLength - wifi_lan_service_info_name_bytes->size()); -} - -Ptr WifiLanServiceInfo::CreateV1Bytes( - PCP::Value pcp, absl::string_view endpoint_id, - ConstPtr service_id_hash) { - Ptr wifi_lan_service_info_name_bytes{ - new ByteArray{kMinLanServiceNameLength}}; - - char* wifi_lan_service_info_name_bytes_write_ptr = - wifi_lan_service_info_name_bytes->getData(); +WifiLanServiceInfo::operator std::string() const { + if (!IsValid()) { + return ""; + } // The upper 3 bits are the Version. - char version_and_pcp_byte = static_cast( + auto version_and_pcp_byte = static_cast( (static_cast(Version::kV1) << 5) & kVersionBitmask); // The lower 5 bits are the PCP. - version_and_pcp_byte |= static_cast(pcp & kPcpBitmask); - *wifi_lan_service_info_name_bytes_write_ptr = version_and_pcp_byte; - wifi_lan_service_info_name_bytes_write_ptr++; + version_and_pcp_byte |= + static_cast(static_cast(pcp_) & kPcpBitmask); - switch (pcp) { - case PCP::P2P_CLUSTER: // Fall through - case PCP::P2P_STAR: // Fall through - case PCP::P2P_POINT_TO_POINT: - // The next 32 bits are the endpoint_id. - if (endpoint_id.size() != kEndpointIdLength) { - // TODO(b/149806065): logger.atDebug().log("Cannot serialize - // WifiLanServiceInfo: V1 Endpoint ID %s (%d bytes) should be exactly - // %d bytes", endpointId, endpointId.length(), ENDPOINT_ID_LENGTH); - return Ptr(); - } - memcpy(wifi_lan_service_info_name_bytes_write_ptr, endpoint_id.data(), - kEndpointIdLength); - wifi_lan_service_info_name_bytes_write_ptr += kEndpointIdLength; + std::string out = absl::StrCat(std::string(1, version_and_pcp_byte), + endpoint_id_, std::string(service_id_hash_)); - // The next 24 bits are the service_id_hash. - if (service_id_hash->size() != kServiceIdHashLength) { - // TODO(b/149806065): logger.atDebug().log("Cannot serialize - // WifiLanServiceInfo: V1 ServiceID hash (%d bytes) should be exactly - // %d bytes", serviceIdHash.length, SERVICE_ID_HASH_LENGTH); - return Ptr(); - } - memcpy(wifi_lan_service_info_name_bytes_write_ptr, - service_id_hash->getData(), kServiceIdHashLength); - wifi_lan_service_info_name_bytes_write_ptr += kServiceIdHashLength; - - // The next bits are the endpoint_name. - // TODO(b/149806065): Implements to parse endpoint_name. - break; - default: - // TODO(b/149806065): logger.atDebug().log("Cannot serialize - // WifiLanServiceInfo: unsupported V1 PCP %d", pcp); - return Ptr(); + // The next bytes are UWB address field. + if (!uwb_address_.Empty()) { + absl::StrAppend(&out, std::string(1, uwb_address_.size())); + absl::StrAppend(&out, std::string(uwb_address_)); + } else { + // Write UWB address with length 0 to be able to read the next field, which + // needs to be appended. + if (web_rtc_state_ != WebRtcState::kUndefined) + absl::StrAppend(&out, std::string(1, uwb_address_.size())); } - return wifi_lan_service_info_name_bytes; + // The next 1 byte is extra field. + if (web_rtc_state_ != WebRtcState::kUndefined) { + int web_rtc_connectable_flag = + (web_rtc_state_ == WebRtcState::kConnectable) ? 1 : 0; + char field_byte = static_cast(web_rtc_connectable_flag) & + kWebRtcConnectableFlagBitmask; + absl::StrAppend(&out, std::string(1, field_byte)); + } + + return Base64Utils::Encode(ByteArray{std::move(out)}); } -WifiLanServiceInfo::WifiLanServiceInfo(Version version, PCP::Value pcp, - absl::string_view endpoint_id, - ConstPtr service_id_hash, - absl::string_view endpoint_name) - : version_(version), - pcp_(pcp), - endpoint_id_(endpoint_id), - service_id_hash_(service_id_hash), - endpoint_name_(endpoint_name) {} +std::string WifiLanServiceInfo::GetEndpointInfoName() const { + return Base64Utils::Encode(endpoint_info_); +} } // namespace connections } // namespace nearby diff --git a/cpp/core/internal/wifi_lan_service_info.h b/cpp/core/internal/wifi_lan_service_info.h index f1114e5f..5a9c58cc 100644 --- a/cpp/core/internal/wifi_lan_service_info.h +++ b/cpp/core/internal/wifi_lan_service_info.h @@ -3,10 +3,9 @@ #include +#include "core/internal/base_pcp_handler.h" #include "core/internal/pcp.h" -#include "platform/byte_array.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "platform/base/byte_array.h" #include "absl/strings/string_view.h" namespace location { @@ -21,72 +20,68 @@ class WifiLanServiceInfo { public: // Versions of the WifiLanServiceInfo. enum class Version { + kUndefined = 0, kV1 = 1, }; - // Static method to deserialize from the encrypted string to - // WifiLanServiceInfo object. - // TODO(b/149762166): Ptr is deprectaed. Uses shrared_ptr or unique_ptr. - static Ptr FromString( - absl::string_view wifi_lan_service_info_string); - - // Static method to serialize to encrypted string from WifiLanServiceInfo - // object. - static std::string AsString(Version version, PCP::Value pcp, - absl::string_view endpoint_id, - ConstPtr service_id_hash); - + // The key of TXTRecord for EndpointInfo. + static constexpr absl::string_view kKeyEndpointInfo{"n"}; static constexpr std::uint32_t kServiceIdHashLength = 3; + static constexpr int kMaxEndpointInfoLength = 131; + WifiLanServiceInfo() = default; + WifiLanServiceInfo(Version version, Pcp pcp, absl::string_view endpoint_id, + const ByteArray& service_id_hash, + const ByteArray& endpoint_info, + const ByteArray& uwb_address, + WebRtcState web_rtc_state); + + // Constructs WifiLanService through packed string of WifiLanServiceInfo and + // EndpointInfo. + // + // service_info_name - A packed string of |WifiLanServiceInfo|. It does + // not include endpoint_info which should be stored + // in next param bleow. + // endpoint_info_name - The endpoint info packed string. + WifiLanServiceInfo(absl::string_view service_info_name, + absl::string_view endpoint_info_name); + WifiLanServiceInfo(const WifiLanServiceInfo&) = default; + WifiLanServiceInfo& operator=(const WifiLanServiceInfo&) = default; + WifiLanServiceInfo(WifiLanServiceInfo&&) = default; + WifiLanServiceInfo& operator=(WifiLanServiceInfo&&) = default; ~WifiLanServiceInfo() = default; - inline Version GetVersion() const { return version_; } - inline PCP::Value GetPcp() const { return pcp_; } - inline std::string GetEndpointId() const { return endpoint_id_; } - inline ConstPtr GetServiceIdHash() const { - return service_id_hash_.get(); - } - inline std::string GetEndpointName() const { return endpoint_name_; } + explicit operator std::string() const; + std::string GetEndpointInfoName() const; + + bool IsValid() const { return !endpoint_id_.empty(); } + Version GetVersion() const { return version_; } + Pcp GetPcp() const { return pcp_; } + std::string GetEndpointId() const { return endpoint_id_; } + ByteArray GetEndpointInfo() const { return endpoint_info_; } + ByteArray GetServiceIdHash() const { return service_id_hash_; } + ByteArray GetUwbAddress() const { return uwb_address_; } + WebRtcState GetWebRtcState() const { return web_rtc_state_; } private: - static Ptr CreateV1WifiLanServiceInfo( - ConstPtr wifi_lan_service_info_name_bytes); - static std::uint32_t ComputeEndpointNameLength( - ConstPtr wifi_lan_service_info_name_bytes); - static Ptr CreateV1Bytes(PCP::Value pcp, - absl::string_view endpoint_id, - ConstPtr service_id_hash); - - // The maximum length of encrypted WifiLanServiceInfo string. - static constexpr int kMaxLanServiceNameLength = 47; - // The minimum length of encrypted WifiLanServiceInfo string. static constexpr int kMinLanServiceNameLength = 9; - // The length for endpoint id in encrypted WifiLanServiceInfo string. static constexpr int kEndpointIdLength = 4; - // The maximum length for endpoint id in encrypted WifiLanServiceInfo string. - static constexpr int kMaxEndpointNameLength = 131; + static constexpr int kUwbAddressLengthSize = 1; + static constexpr int kExtraFieldLength = 1; - static constexpr uint16 kVersionBitmask = 0x0E0; - static constexpr uint16 kPcpBitmask = 0x01F; - static constexpr uint16 kVersionShift = 5; + static constexpr int kVersionBitmask = 0x0E0; + static constexpr int kPcpBitmask = 0x01F; + static constexpr int kVersionShift = 5; + static constexpr int kWebRtcConnectableFlagBitmask = 0x01; - WifiLanServiceInfo(Version version, PCP::Value pcp, - absl::string_view endpoint_id, - ConstPtr service_id_hash, - absl::string_view endpoint_name); - - // WifiLanServiceInfo version. - const Version version_; - // Pre-Connection Protocols version. - const PCP::Value pcp_; - // Connected endpoint id. - const std::string endpoint_id_; - // Connected hash service id. - ScopedPtr > service_id_hash_; - // TODO(b/149806065): Replaces endpointName as endPointInfo eventually; - // it is not in this version yet for endpointName. - // Connected endpoint name. - const std::string endpoint_name_; + Version version_{Version::kUndefined}; + Pcp pcp_{Pcp::kUnknown}; + std::string endpoint_id_; + ByteArray service_id_hash_; + ByteArray endpoint_info_; + // TODO(b/169550050): Define UWB address field. + ByteArray uwb_address_; + WebRtcState web_rtc_state_{WebRtcState::kUndefined}; }; } // namespace connections diff --git a/cpp/core/internal/wifi_lan_service_info_test.cc b/cpp/core/internal/wifi_lan_service_info_test.cc index 7b7c5ced..3463a18b 100644 --- a/cpp/core/internal/wifi_lan_service_info_test.cc +++ b/cpp/core/internal/wifi_lan_service_info_test.cc @@ -1,9 +1,9 @@ #include "core/internal/wifi_lan_service_info.h" #include +#include -#include "platform/base64_utils.h" -#include "platform/port/string.h" +#include "platform/base/base64_utils.h" #include "gtest/gtest.h" namespace location { @@ -11,138 +11,180 @@ namespace nearby { namespace connections { namespace { -const WifiLanServiceInfo::Version kVersion = WifiLanServiceInfo::Version::kV1; -const PCP::Value kPcp = PCP::P2P_CLUSTER; -const char kEndPointID[] = "AB12"; -const char kServiceIDHashBytes[] = {0x0A, 0x0B, 0x0C}; -// TODO(b/149806065): Implements test endpoint_name. +constexpr WifiLanServiceInfo::Version kVersion = + WifiLanServiceInfo::Version::kV1; +constexpr Pcp kPcp = Pcp::kP2pCluster; +constexpr absl::string_view kEndPointID{"AB12"}; +constexpr absl::string_view kServiceIDHashBytes{"\x0a\x0b\x0c"}; +constexpr absl::string_view kEndPointName{"RAWK + ROWL!"}; +constexpr WebRtcState kWebRtcState = WebRtcState::kConnectable; -TEST(WifiLanServiceInfoTest, SerializationDeserializationWorks) { - ScopedPtr > scoped_service_id_hash(new ByteArray( - kServiceIDHashBytes, sizeof(kServiceIDHashBytes) / sizeof(char))); +// TODO(b/169550050): Implement UWBAddress. +TEST(WifiLanServiceInfoTest, ConstructionWorks) { + ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; + ByteArray endpoint_info{std::string(kEndPointName)}; + WifiLanServiceInfo wifi_lan_service_info{kVersion, + kPcp, + kEndPointID, + service_id_hash, + endpoint_info, + ByteArray{}, + kWebRtcState}; - std::string wifi_lan_service_info_string = WifiLanServiceInfo::AsString( - kVersion, kPcp, kEndPointID, ConstifyPtr(scoped_service_id_hash.get())); - ScopedPtr > scoped_wifi_lan_service_info( - WifiLanServiceInfo::FromString(wifi_lan_service_info_string)); - - EXPECT_EQ(kPcp, scoped_wifi_lan_service_info->GetPcp()); - EXPECT_EQ(kVersion, scoped_wifi_lan_service_info->GetVersion()); - EXPECT_EQ(kEndPointID, scoped_wifi_lan_service_info->GetEndpointId()); - EXPECT_EQ(*scoped_service_id_hash, - *(scoped_wifi_lan_service_info->GetServiceIdHash())); + EXPECT_TRUE(wifi_lan_service_info.IsValid()); + EXPECT_EQ(kPcp, wifi_lan_service_info.GetPcp()); + EXPECT_EQ(kVersion, wifi_lan_service_info.GetVersion()); + EXPECT_EQ(kEndPointID, wifi_lan_service_info.GetEndpointId()); + EXPECT_EQ(service_id_hash, wifi_lan_service_info.GetServiceIdHash()); + EXPECT_EQ(endpoint_info, wifi_lan_service_info.GetEndpointInfo()); } -TEST(WifiLanServiceInfoTest, - SerializationDeserializationWorksWithEmptyEndpointName) { - ScopedPtr > scoped_service_id_hash(new ByteArray( - kServiceIDHashBytes, sizeof(kServiceIDHashBytes) / sizeof(char))); +TEST(WifiLanServiceInfoTest, ConstructionFromSerializedStringWorks) { + ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; + ByteArray endpoint_info{std::string(kEndPointName)}; + WifiLanServiceInfo org_wifi_lan_service_info{kVersion, + kPcp, + kEndPointID, + service_id_hash, + endpoint_info, + ByteArray{}, + kWebRtcState}; + std::string wifi_lan_service_info_string{org_wifi_lan_service_info}; + auto endpoint_info_name = org_wifi_lan_service_info.GetEndpointInfoName(); - std::string wifi_lan_service_info_string = WifiLanServiceInfo::AsString( - kVersion, kPcp, kEndPointID, ConstifyPtr(scoped_service_id_hash.get())); - ScopedPtr > scoped_wifi_lan_service_info( - WifiLanServiceInfo::FromString(wifi_lan_service_info_string)); + WifiLanServiceInfo wifi_lan_service_info{wifi_lan_service_info_string, + endpoint_info_name}; - EXPECT_EQ(kPcp, scoped_wifi_lan_service_info->GetPcp()); - EXPECT_EQ(kVersion, scoped_wifi_lan_service_info->GetVersion()); - EXPECT_EQ(kEndPointID, scoped_wifi_lan_service_info->GetEndpointId()); - EXPECT_EQ(*scoped_service_id_hash, - *(scoped_wifi_lan_service_info->GetServiceIdHash())); + EXPECT_TRUE(wifi_lan_service_info.IsValid()); + EXPECT_EQ(kPcp, wifi_lan_service_info.GetPcp()); + EXPECT_EQ(kVersion, wifi_lan_service_info.GetVersion()); + EXPECT_EQ(kEndPointID, wifi_lan_service_info.GetEndpointId()); + EXPECT_EQ(service_id_hash, wifi_lan_service_info.GetServiceIdHash()); + EXPECT_EQ(endpoint_info, wifi_lan_service_info.GetEndpointInfo()); + EXPECT_EQ(kWebRtcState, wifi_lan_service_info.GetWebRtcState()); } -TEST(WifiLanServiceInfoTest, SerializationFailsWithBadVersion) { - WifiLanServiceInfo::Version bad_version = - static_cast(666); +TEST(WifiLanServiceInfoTest, ConstructionFailsWithBadVersion) { + auto bad_version = static_cast(666); - ScopedPtr > scoped_service_id_hash(new ByteArray( - kServiceIDHashBytes, sizeof(kServiceIDHashBytes) / sizeof(char))); + ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; + ByteArray endpoint_info{std::string(kEndPointName)}; + WifiLanServiceInfo wifi_lan_service_info{bad_version, + kPcp, + kEndPointID, + service_id_hash, + endpoint_info, + ByteArray{}, + kWebRtcState}; - std::string wifi_lan_service_info_string = - WifiLanServiceInfo::AsString(bad_version, kPcp, kEndPointID, - ConstifyPtr(scoped_service_id_hash.get())); - - EXPECT_TRUE(wifi_lan_service_info_string.empty()); + EXPECT_FALSE(wifi_lan_service_info.IsValid()); } -TEST(WifiLanServiceInfoTest, SerializationFailsWithBadPCP) { - PCP::Value bad_pcp = static_cast(666); +TEST(WifiLanServiceInfoTest, ConstructionFailsWithBadPCP) { + auto bad_pcp = static_cast(666); - ScopedPtr > scoped_service_id_hash(new ByteArray( - kServiceIDHashBytes, sizeof(kServiceIDHashBytes) / sizeof(char))); + ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; + ByteArray endpoint_info{std::string(kEndPointName)}; + WifiLanServiceInfo wifi_lan_service_info{kVersion, + bad_pcp, + kEndPointID, + service_id_hash, + endpoint_info, + ByteArray{}, + kWebRtcState}; - std::string wifi_lan_service_info_string = - WifiLanServiceInfo::AsString(kVersion, bad_pcp, kEndPointID, - ConstifyPtr(scoped_service_id_hash.get())); - - EXPECT_TRUE(wifi_lan_service_info_string.empty()); + EXPECT_FALSE(wifi_lan_service_info.IsValid()); } -TEST(WifiLanServiceInfoTest, SerializationFailsWithShortEndpointId) { +TEST(WifiLanServiceInfoTest, ConstructionFailsWithShortEndpointId) { std::string short_endpoint_id("AB1"); - ScopedPtr > scoped_service_id_hash(new ByteArray( - kServiceIDHashBytes, sizeof(kServiceIDHashBytes) / sizeof(char))); + ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; + ByteArray endpoint_info{std::string(kEndPointName)}; + WifiLanServiceInfo wifi_lan_service_info{kVersion, + kPcp, + short_endpoint_id, + service_id_hash, + endpoint_info, + ByteArray{}, + kWebRtcState}; - std::string wifi_lan_service_info_string = - WifiLanServiceInfo::AsString(kVersion, kPcp, short_endpoint_id, - ConstifyPtr(scoped_service_id_hash.get())); - - EXPECT_TRUE(wifi_lan_service_info_string.empty()); + EXPECT_FALSE(wifi_lan_service_info.IsValid()); } -TEST(WifiLanServiceInfoTest, SerializationFailsWithLongEndpointId) { +TEST(WifiLanServiceInfoTest, ConstructionFailsWithLongEndpointId) { std::string long_endpoint_id("AB12X"); - ScopedPtr > scoped_service_id_hash(new ByteArray( - kServiceIDHashBytes, sizeof(kServiceIDHashBytes) / sizeof(char))); + ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; + ByteArray endpoint_info{std::string(kEndPointName)}; + WifiLanServiceInfo wifi_lan_service_info{kVersion, + kPcp, + long_endpoint_id, + service_id_hash, + endpoint_info, + ByteArray{}, + kWebRtcState}; - std::string wifi_lan_service_info_string = - WifiLanServiceInfo::AsString(kVersion, kPcp, long_endpoint_id, - ConstifyPtr(scoped_service_id_hash.get())); - - EXPECT_TRUE(wifi_lan_service_info_string.empty()); + EXPECT_FALSE(wifi_lan_service_info.IsValid()); } -TEST(WifiLanServiceInfoTest, SerializationFailsWithShortServiceIdHash) { - char short_service_id_hash_bytes[] = {0x0A, 0x0B}; +TEST(WifiLanServiceInfoTest, ConstructionFailsWithShortServiceIdHash) { + char short_service_id_hash_bytes[] = "\x0a\x0b"; - ScopedPtr > scoped_short_service_id_hash( - new ByteArray(short_service_id_hash_bytes, - sizeof(short_service_id_hash_bytes) / sizeof(char))); + ByteArray short_service_id_hash{short_service_id_hash_bytes}; + ByteArray endpoint_info{std::string(kEndPointName)}; + WifiLanServiceInfo wifi_lan_service_info{kVersion, + kPcp, + kEndPointID, + short_service_id_hash, + endpoint_info, + ByteArray{}, + kWebRtcState}; - std::string wifi_lan_service_info_string = WifiLanServiceInfo::AsString( - kVersion, kPcp, kEndPointID, - ConstifyPtr(scoped_short_service_id_hash.get())); - - EXPECT_TRUE(wifi_lan_service_info_string.empty()); + EXPECT_FALSE(wifi_lan_service_info.IsValid()); } -TEST(WifiLanServiceInfoTest, SerializationFailsWithLongServiceIdHash) { - char long_service_id_hash_bytes[] = {0x0A, 0x0B, 0x0C, 0x0D}; +TEST(WifiLanServiceInfoTest, ConstructionFailsWithLongServiceIdHash) { + char long_service_id_hash_bytes[] = "\x0a\x0b\x0c\x0d"; - ScopedPtr > scoped_long_service_id_hash( - new ByteArray(long_service_id_hash_bytes, - sizeof(long_service_id_hash_bytes) / sizeof(char))); + ByteArray long_service_id_hash{long_service_id_hash_bytes}; + ByteArray endpoint_info{std::string(kEndPointName)}; + WifiLanServiceInfo wifi_lan_service_info{kVersion, + kPcp, + kEndPointID, + long_service_id_hash, + endpoint_info, + ByteArray{}, + kWebRtcState}; - std::string wifi_lan_service_info_string = WifiLanServiceInfo::AsString( - kVersion, kPcp, kEndPointID, - ConstifyPtr(scoped_long_service_id_hash.get())); - - EXPECT_TRUE(wifi_lan_service_info_string.empty()); + EXPECT_FALSE(wifi_lan_service_info.IsValid()); } -TEST(WifiLanServiceInfoTest, DeserializationFailsWithShortLength) { - char wifi_lan_service_info_bytes[] = {'X'}; +TEST(WifiLanServiceInfoTest, ConstructionFailsWithShortStringLength) { + char wifi_lan_service_info_string[] = {'X', '\0'}; + ByteArray endpoint_info{std::string(kEndPointName)}; - ScopedPtr > scoped_wifi_lan_service_info_bytes( - new ByteArray(wifi_lan_service_info_bytes, - sizeof(wifi_lan_service_info_bytes) / sizeof(char))); + ByteArray wifi_lan_service_info_bytes{wifi_lan_service_info_string}; + WifiLanServiceInfo wifi_lan_service_info{ + Base64Utils::Encode(wifi_lan_service_info_bytes), + Base64Utils::Encode(endpoint_info)}; - ScopedPtr > scoped_wifi_lan_service_info( - WifiLanServiceInfo::FromString(Base64Utils::encode( - ConstifyPtr(scoped_wifi_lan_service_info_bytes.get())))); + EXPECT_FALSE(wifi_lan_service_info.IsValid()); +} - EXPECT_TRUE(scoped_wifi_lan_service_info.isNull()); +TEST(WifiLanServiceInfoTest, ConstructionFailsWithLongEndpointInfoLength) { + ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; + ByteArray long_endpoint_info(WifiLanServiceInfo::kMaxEndpointInfoLength + 1); + + WifiLanServiceInfo wifi_lan_service_info{kVersion, + kPcp, + kEndPointID, + service_id_hash, + long_endpoint_info, + ByteArray{}, + kWebRtcState}; + + EXPECT_FALSE(wifi_lan_service_info.IsValid()); } } // namespace diff --git a/cpp/core/internal/wifi_lan_upgrade_handler.cc b/cpp/core/internal/wifi_lan_upgrade_handler.cc deleted file mode 100644 index 00639406..00000000 --- a/cpp/core/internal/wifi_lan_upgrade_handler.cc +++ /dev/null @@ -1,63 +0,0 @@ -#include "core/internal/wifi_lan_upgrade_handler.h" -#include "proto/connections_enums.pb.h" - -namespace location { -namespace nearby { -namespace connections { - -namespace wifi_lan_upgrade_handler { - -template -class OnIncomingWifiConnectionRunnable : public Runnable { - public: - void run() {} -}; - -} // namespace wifi_lan_upgrade_handler - -template -WifiLanUpgradeHandler::WifiLanUpgradeHandler( - Ptr > medium_manager, - Ptr endpoint_channel_manager) - : BaseBandwidthUpgradeHandler(endpoint_channel_manager), - medium_manager_(medium_manager) {} - -template -WifiLanUpgradeHandler::~WifiLanUpgradeHandler() {} - -template -proto::connections::Medium WifiLanUpgradeHandler::getUpgradeMedium() { - return proto::connections::Medium::WIFI_LAN; -} - -template -void WifiLanUpgradeHandler::revertImpl() {} - -template -void WifiLanUpgradeHandler::onIncomingWifiConnection( - Ptr socket) {} - -// TODO(ahlee): This will differ from the Java code (previously threw an -// UpgradeException). Leaving the return type simple for the skeleton - I'll -// switch to a pair if the result enum is needed. -template -ConstPtr -WifiLanUpgradeHandler::initializeUpgradedMediumForEndpoint( - const string& endpoint_id) { - return ConstPtr(); -} - -// TODO(ahlee): This will differ from the Java code (previously threw an -// exception). -template -Ptr -WifiLanUpgradeHandler::createUpgradedEndpointChannel( - const string& endpoint_id, - ConstPtr - upgrade_path_info) { - return Ptr(); -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core/internal/wifi_lan_upgrade_handler.h b/cpp/core/internal/wifi_lan_upgrade_handler.h deleted file mode 100644 index 1b4d4d1a..00000000 --- a/cpp/core/internal/wifi_lan_upgrade_handler.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef CORE_INTERNAL_WIFI_LAN_UPGRADE_HANDLER_H_ -#define CORE_INTERNAL_WIFI_LAN_UPGRADE_HANDLER_H_ - -#include "core/internal/base_bandwidth_upgrade_handler.h" -#include "core/internal/endpoint_channel_manager.h" -#include "core/internal/medium_manager.h" -#include "proto/connections/offline_wire_formats.pb.h" -#include "platform/api/socket.h" -#include "platform/port/string.h" -#include "platform/ptr.h" -#include "proto/connections_enums.pb.h" - -namespace location { -namespace nearby { -namespace connections { - -namespace wifi_lan_upgrade_handler { - -template -class OnIncomingWifiConnectionRunnable; - -} // namespace wifi_lan_upgrade_handler - -// Manages the WIFI_LAN-specific methods needed to upgrade an EndpointChannel -template -class WifiLanUpgradeHandler : public BaseBandwidthUpgradeHandler { - // TODO(ahlee): Uncomment when WIFI_LAN plumbing is done. - // public MediumManager::IncomingWifiConnectionProcessor { - public: - WifiLanUpgradeHandler(Ptr > medium_manager_, - Ptr endpoint_channel_manager); - ~WifiLanUpgradeHandler() override; - - void onIncomingWifiConnection(Ptr socket); - - protected: - // @BandwidthUpgradeHandlerThread - ConstPtr initializeUpgradedMediumForEndpoint( - const string& endpoint_id) override; - // @BandwidthUpgradeHandlerThread - Ptr createUpgradedEndpointChannel( - const string& endpoint_id, - ConstPtr - upgrade_path_info) override; - // TODO(ahlee): Change the java counterparts of these methods to private. - proto::connections::Medium getUpgradeMedium() override; - // @BandwidthUpgradeHandlerThread - void revertImpl() override; - - private: - class IncomingWifiLanSocketConnection - : public BaseBandwidthUpgradeHandler::IncomingSocketConnection { - public: - explicit IncomingWifiLanSocketConnection(Ptr socket) - : new_endpoint_channel_(Ptr()), - // TODO(ahlee): Uncomment when plumbing for WIFI_LAN is done. - // new_endpoint_channel_(getEndpointChannelManager() - // .createOutgoingWifiLanEndpointChannel(socket)), - wifi_socket_(socket) {} - // TODO(ahlee): This is only used for logging which is not currently - // implemented. If we want to match the Java code in the future, we'll need - // to add toString() to socket.h. - string socketToString() override { return string(); } - void closeSocket() override { - // Ignore the potential Exception returned by close(), as a counterpart - // to Java's closeQuietly(). - wifi_socket_->close(); - } - // TODO(ahlee): Double check that the ownership of this is correct when - // this is fully implemented. - Ptr getEndpointChannel() override { - return new_endpoint_channel_.release(); - } - - private: - ScopedPtr > new_endpoint_channel_; - Ptr wifi_socket_; - }; - - template - friend class wifi_lan_upgrade_handler::OnIncomingWifiConnectionRunnable; - - Ptr > medium_manager_; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#include "core/internal/wifi_lan_upgrade_handler.cc" - -#endif // CORE_INTERNAL_WIFI_LAN_UPGRADE_HANDLER_H_ diff --git a/cpp/core/listeners.h b/cpp/core/listeners.h index 28ab7a30..c49b3831 100644 --- a/cpp/core/listeners.h +++ b/cpp/core/listeners.h @@ -2,162 +2,173 @@ #define CORE_LISTENERS_H_ #include +#include +#include +#include +// This file defines all the protocol listeners and their parameter structures. +// Listeners are defined as collections of std::function instances, which is +// more flexible than a virtual function: +// - a subset of listener callbacks may be overridden, while others may remain +// default-initialized. +// - callbacks may be initialized with lambdas; lambda definitions are concize. + +#include "core/options.h" #include "core/payload.h" #include "core/status.h" -#include "platform/byte_array.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "platform/base/byte_array.h" +#include "platform/base/listeners.h" namespace location { namespace nearby { namespace connections { -struct OnConnectionInitiatedParams { - const std::string remote_endpoint_id; - const std::string remote_endpoint_name; - const std::string authentication_token; - ConstPtr raw_authentication_token; - const bool is_incoming_connection; - - OnConnectionInitiatedParams(const std::string& remote_endpoint_id, - const std::string& remote_endpoint_name, - const std::string& authentication_token, - ConstPtr raw_authentication_token, - bool is_incoming_connection) - : remote_endpoint_id(remote_endpoint_id), - remote_endpoint_name(remote_endpoint_name), - authentication_token(authentication_token), - raw_authentication_token(raw_authentication_token), - is_incoming_connection(is_incoming_connection) {} +// Common callback for asynchronously invoked methods. +// Called after a job scheduled for execution is completed. +// This is not the same as completion of the associated process, +// which may have many states, and multiple async jobs, and be still ongoing. +// Progress on the overall process is reported by the associated listener. +struct ResultCallback { + // Callback to access the status of the operation when available. + // status - result of job execution; + // Status::kSuccess, if successful; anything else indicates failure. + std::function result_cb = DefaultCallback(); }; -struct OnConnectionResultParams { - const std::string remote_endpoint_id; - const Status::Value status; - - OnConnectionResultParams(const std::string& remote_endpoint_id, - Status::Value status) - : remote_endpoint_id(remote_endpoint_id), status(status) {} +struct ConnectionResponseInfo { + ByteArray remote_endpoint_info; + std::string authentication_token; + ByteArray raw_authentication_token; + bool is_incoming_connection = false; + bool is_connection_verified = false; }; -struct OnDisconnectedParams { - const std::string remote_endpoint_id; - - explicit OnDisconnectedParams(const std::string& remote_endpoint_id) - : remote_endpoint_id(remote_endpoint_id) {} +struct PayloadProgressInfo { + std::int64_t payload_id = 0; + enum class Status { + kSuccess, + kFailure, + kInProgress, + kCanceled, + } status = Status::kSuccess; + std::int64_t total_bytes = 0; + std::int64_t bytes_transferred = 0; }; -struct OnBandwidthChangedParams { - const std::string remote_endpoint_id; - const std::int32_t quality; - - OnBandwidthChangedParams(const std::string& remote_endpoint_id, - std::int32_t quality) - : remote_endpoint_id(remote_endpoint_id), quality(quality) {} +enum class DistanceInfo { + kUnknown = 1, + kVeryClose = 2, + kClose = 3, + kFar = 4, }; -struct OnPayloadReceivedParams { - const std::string remote_endpoint_id; - const ConstPtr payload; +struct ConnectionListener { + // A basic encrypted channel has been created between you and the endpoint. + // Both sides are now asked if they wish to accept or reject the connection + // before any data can be sent over this channel. + // + // This is your chance, before you accept the connection, to confirm that you + // connected to the correct device. Both devices are given an identical token; + // it's up to you to decide how to verify it before proceeding. Typically this + // involves showing the token on both devices and having the users manually + // compare and confirm; however, this is only required if you desire a secure + // connection between the devices. + // + // Whichever route you decide to take (including not authenticating the other + // device), call Core::AcceptConnection() when you're ready to talk, or + // Core::RejectConnection() to close the connection. + // + // endpoint_id - The identifier for the remote endpoint. + // info - Other relevant information about the connection. + std::function + initiated_cb = + DefaultCallback(); - OnPayloadReceivedParams(const std::string& remote_endpoint_id, - ConstPtr payload) - : remote_endpoint_id(remote_endpoint_id), payload(payload) {} + // Called after both sides have accepted the connection. + // Both sides may now send Payloads to each other. + // Call Core::SendPayload() or wait for incoming PayloadListener::OnPayload(). + // + // endpoint_id - The identifier for the remote endpoint. + std::function accepted_cb = + DefaultCallback(); + + // Called when either side rejected the connection. + // Payloads can not be exchaged. Call Core::DisconnectFromEndpoint() + // to terminate connection. + // + // endpoint_id - The identifier for the remote endpoint. + std::function + rejected_cb = DefaultCallback(); + + // Called when a remote endpoint is disconnected or has become unreachable. + // At this point service (re-)discovery may start again. + // + // endpoint_id - The identifier for the remote endpoint. + std::function disconnected_cb = + DefaultCallback(); + + // Called when the connection's available bandwidth has changed. + // + // endpoint_id - The identifier for the remote endpoint. + // medium - Medium we upgraded to. + std::function + bandwidth_changed_cb = DefaultCallback(); }; -struct PayloadTransferUpdate { - const std::int64_t payload_id; - struct Status { - enum Value { - SUCCESS, - FAILURE, - IN_PROGRESS, - CANCELED, - }; - }; - const Status::Value status; - const std::int64_t total_bytes; - const std::int64_t bytes_transferred; +struct DiscoveryListener { + // Called when a remote endpoint is discovered. + // + // endpoint_id - The ID of the remote endpoint that was discovered. + // endpoint_info - The info of the remote endpoint representd by ByteArray. + // service_id - The ID of the service advertised by the remote endpoint. + std::function + endpoint_found_cb = DefaultCallback(); - PayloadTransferUpdate(std::int64_t payload_id, Status::Value status, - std::int64_t total_bytes, - std::int64_t bytes_transferred) - : payload_id(payload_id), - status(status), - total_bytes(total_bytes), - bytes_transferred(bytes_transferred) {} + // Called when a remote endpoint is no longer discoverable; only called for + // endpoints that previously had been passed to {@link + // #onEndpointFound(String, DiscoveredEndpointInfo)}. + // + // endpoint_id - The ID of the remote endpoint that was lost. + std::function endpoint_lost_cb = + DefaultCallback(); + + // Called when a remote endpoint is found with an updated distance. + // + // arguments: + // endpoint_id - The ID of the remote endpoint that was lost. + // info - The distance info, encoded as enum value. + std::function + endpoint_distance_changed_cb = + DefaultCallback(); }; -struct OnPayloadTransferUpdateParams { - const std::string remote_endpoint_id; - const PayloadTransferUpdate update; +struct PayloadListener { + // Called when a Payload is received from a remote endpoint. Depending + // on the type of the Payload, all of the data may or may not have been + // received at the time of this call. Use OnPayloadProgress() to + // get updates on the status of the data received. + // + // endpoint_id - The identifier for the remote endpoint that sent the + // payload. + // payload - The Payload object received. + std::function + payload_cb = DefaultCallback(); - OnPayloadTransferUpdateParams(const std::string& remote_endpoint_id, - const PayloadTransferUpdate& update) - : remote_endpoint_id(remote_endpoint_id), update(update) {} -}; - -struct OnEndpointFoundParams { - const std::string endpoint_id; - const std::string service_id; - const std::string endpoint_name; - - OnEndpointFoundParams(const std::string& endpoint_id, - const std::string& service_id, - const std::string& endpoint_name) - : endpoint_id(endpoint_id), - service_id(service_id), - endpoint_name(endpoint_name) {} -}; - -struct OnEndpointLostParams { - const std::string endpoint_id; - - explicit OnEndpointLostParams(const std::string& endpoint_id) - : endpoint_id(endpoint_id) {} -}; - -class ResultListener { - public: - virtual ~ResultListener() {} - - virtual void onResult(Status::Value status) = 0; -}; - -class ConnectionLifecycleListener { - public: - virtual ~ConnectionLifecycleListener() {} - - virtual void onConnectionInitiated( - ConstPtr on_connection_initiated_params) = 0; - virtual void onConnectionResult( - ConstPtr on_connection_result_params) = 0; - virtual void onDisconnected( - ConstPtr on_disconnected_params) = 0; - virtual void onBandwidthChanged( - ConstPtr on_bandwidth_changed_params) = 0; -}; - -class DiscoveryListener { - public: - virtual ~DiscoveryListener() {} - - virtual void onEndpointFound( - ConstPtr on_endpoint_found_params) = 0; - virtual void onEndpointLost( - ConstPtr on_endpoint_lost_params) = 0; -}; - -class PayloadListener { - public: - virtual ~PayloadListener() {} - - virtual void onPayloadReceived( - ConstPtr on_payload_received_params) = 0; - virtual void onPayloadTransferUpdate( - ConstPtr - on_payload_transfer_update_params) = 0; + // Called with progress information about an active Payload transfer, either + // incoming or outgoing. + // + // endpoint_id - The identifier for the remote endpoint that is sending or + // receiving this payload. + // info - The PayloadProgressInfo structure describing the status of + // the transfer. + std::function + payload_progress_cb = + DefaultCallback(); }; } // namespace connections diff --git a/cpp/core_v2/listeners_test.cc b/cpp/core/listeners_test.cc similarity index 97% rename from cpp/core_v2/listeners_test.cc rename to cpp/core/listeners_test.cc index 270c412c..9b7d02c7 100644 --- a/cpp/core_v2/listeners_test.cc +++ b/cpp/core/listeners_test.cc @@ -1,4 +1,4 @@ -#include "core_v2/listeners.h" +#include "core/listeners.h" #include #include diff --git a/cpp/core/options.h b/cpp/core/options.h index 222f0060..bb65b4b8 100644 --- a/cpp/core/options.h +++ b/cpp/core/options.h @@ -2,27 +2,134 @@ #define CORE_OPTIONS_H_ #include "core/strategy.h" +#include "platform/base/byte_array.h" +#include "proto/connections_enums.pb.h" +#include "proto/connections_enums.pb.h" namespace location { namespace nearby { namespace connections { -struct AdvertisingOptions { - const Strategy strategy; - const bool auto_upgrade_bandwidth; - const bool enforce_topology_constraints; +using Medium = ::location::nearby::proto::connections::Medium; - AdvertisingOptions(Strategy strategy, bool auto_upgrade_bandwidth, - bool enforce_topology_constraints) - : strategy(strategy), - auto_upgrade_bandwidth(auto_upgrade_bandwidth), - enforce_topology_constraints(enforce_topology_constraints) {} +// Generic type: allows definition of a feature T for every Medium. +template +struct MediumSelector { + T bluetooth; + T ble; + T web_rtc; + T wifi_lan; + + constexpr MediumSelector() = default; + constexpr MediumSelector(const MediumSelector&) = default; + constexpr MediumSelector& operator=(const MediumSelector&) = default; + + constexpr bool Any(T value) const { + return bluetooth == value || ble == value || web_rtc == value || + wifi_lan == value; + } + + constexpr bool All(T value) const { + return bluetooth == value && ble == value && web_rtc == value && + wifi_lan == value; + } + + constexpr int Count(T value) const { + int count = 0; + if (bluetooth == value) count++; + if (ble == value) count++; + if (wifi_lan == value) count++; + if (web_rtc == value) count++; + return count; + } + + constexpr MediumSelector& SetAll(T value) { + bluetooth = value; + ble = value; + web_rtc = value; + wifi_lan = value; + return *this; + } + + std::vector GetMediums(T value) const { + std::vector mediums; + // Mediums are sorted in order of decreasing preference. + if (wifi_lan == value) mediums.push_back(Medium::WIFI_LAN); + if (web_rtc == value) mediums.push_back(Medium::WEB_RTC); + if (bluetooth == value) mediums.push_back(Medium::BLUETOOTH); + if (ble == value) mediums.push_back(Medium::BLE); + return mediums; + } }; -struct DiscoveryOptions { - const Strategy strategy; +// Feature On/Off switch for mediums. +using BooleanMediumSelector = MediumSelector; - explicit DiscoveryOptions(Strategy strategy) : strategy(strategy) {} +// Represents the various power levels that can be used, on mediums that support +// it. +enum class PowerLevel { + kHighPower = 0, + kLowPower = 1, +}; + +// Connection Options: used for both Advertising and Discovery. +// All fields are mutable, to make the type copy-assignable. +struct ConnectionOptions { + Strategy strategy; + BooleanMediumSelector allowed{BooleanMediumSelector().SetAll(true)}; + bool auto_upgrade_bandwidth; + bool enforce_topology_constraints; + bool low_power; + bool enable_bluetooth_listening; + // Whether this is intended to be used in conjunction with InjectEndpoint(). + bool is_out_of_band_connection = false; + ByteArray remote_bluetooth_mac_address; + std::string fast_advertisement_service_uuid; + // Verify if ConnectionOptions is in a not-initialized (Empty) state. + bool Empty() const { return strategy.IsNone(); } + // Bring ConnectionOptions to a not-initialized (Empty) state. + void Clear() { strategy.Clear(); } + // Returns a copy and normalizes allowed mediums: + // (1) If is_out_of_band_connection is true, verifies that there is only one + // medium allowed, defaulting to only Bluetooth if unspecified. + // (2) If no mediums are allowed, allow all mediums. + ConnectionOptions CompatibleOptions() const { + ConnectionOptions result = *this; + + // Out-of-band connections initiate connections via an injected endpoint + // rather than through the normal discovery flow. These types of connections + // can only be injected via a single medium. + if (is_out_of_band_connection) { + int num_enabled = result.allowed.Count(true); + + // Default to allow only Bluetooth if no single medium is specified. + if (num_enabled != 1) { + result.allowed.SetAll(false); + result.allowed.bluetooth = true; + } + + return result; + } + + // Normal connections (i.e., not out-of-band) connections can specify + // multiple mediums. If none are specified, default to allowing all mediums. + if (!allowed.Any(true)) + result.allowed.SetAll(true); + return result; + } + std::vector GetMediums() const { return allowed.GetMediums(true); } +}; + +// Metadata injected to facilitate out-of-band connections. The medium field is +// required, and the other fields are only specified for a specific medium. +// Currently, Bluetooth is the only supported medium for out-of-band +// connections. +struct OutOfBandConnectionMetadata { + // Medium to use for the out-of-band connection. + Medium medium; + + // Used for Bluetooth connections. + ByteArray remote_bluetooth_mac_address; }; } // namespace connections diff --git a/cpp/core/params.h b/cpp/core/params.h index 754d0ec6..bd3918e3 100644 --- a/cpp/core/params.h +++ b/cpp/core/params.h @@ -1,144 +1,24 @@ #ifndef CORE_PARAMS_H_ #define CORE_PARAMS_H_ -#include -#include +#include #include "core/listeners.h" -#include "core/options.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "platform/base/byte_array.h" namespace location { namespace nearby { namespace connections { -struct StartAdvertisingParams { - Ptr result_listener; - const std::string name; - const std::string service_id; - const AdvertisingOptions advertising_options; - Ptr connection_lifecycle_listener; - - StartAdvertisingParams( - Ptr result_listener, const std::string& name, - const std::string& service_id, - const AdvertisingOptions& advertising_options, - Ptr connection_lifecycle_listener) - : result_listener(result_listener), - name(name), - service_id(service_id), - advertising_options(advertising_options), - connection_lifecycle_listener(connection_lifecycle_listener) {} -}; - -struct StopAdvertisingParams { - // Intentionally left empty. -}; - -struct StartDiscoveryParams { - Ptr result_listener; - const std::string service_id; - const DiscoveryOptions discovery_options; - Ptr discovery_listener; - - StartDiscoveryParams(Ptr result_listener, - const std::string& service_id, - const DiscoveryOptions& discovery_options, - Ptr discovery_listener) - : result_listener(result_listener), - service_id(service_id), - discovery_options(discovery_options), - discovery_listener(discovery_listener) {} -}; - -struct StopDiscoveryParams { - // Intentionally left empty. -}; - -struct RequestConnectionParams { - Ptr result_listener; - const std::string name; - const std::string remote_endpoint_id; - Ptr connection_lifecycle_listener; - - RequestConnectionParams( - Ptr result_listener, const std::string& name, - const std::string& remote_endpoint_id, - Ptr connection_lifecycle_listener) - : result_listener(result_listener), - name(name), - remote_endpoint_id(remote_endpoint_id), - connection_lifecycle_listener(connection_lifecycle_listener) {} -}; - -struct AcceptConnectionParams { - Ptr result_listener; - const std::string remote_endpoint_id; - Ptr payload_listener; - - AcceptConnectionParams(Ptr result_listener, - const std::string& remote_endpoint_id, - Ptr payload_listener) - : result_listener(result_listener), - remote_endpoint_id(remote_endpoint_id), - payload_listener(payload_listener) {} -}; - -struct RejectConnectionParams { - Ptr result_listener; - const std::string remote_endpoint_id; - - RejectConnectionParams(Ptr result_listener, - const std::string& remote_endpoint_id) - : result_listener(result_listener), - remote_endpoint_id(remote_endpoint_id) {} -}; - -struct SendPayloadParams { - Ptr result_listener; - const std::vector remote_endpoint_ids; - ConstPtr payload; - - SendPayloadParams(Ptr result_listener, - const std::vector& remote_endpoint_ids, - ConstPtr payload) - : result_listener(result_listener), - remote_endpoint_ids(remote_endpoint_ids), - payload(payload) {} -}; - -struct CancelPayloadParams { - Ptr result_listener; - const std::int64_t payload_id; - - CancelPayloadParams(Ptr result_listener, - std::int64_t payload_id) - : result_listener(result_listener), payload_id(payload_id) {} -}; - -struct InitiateBandwidthUpgradeParams { - Ptr result_listener; - const std::string remote_endpoint_id; - - InitiateBandwidthUpgradeParams(Ptr result_listener, - const std::string& remote_endpoint_id) - : result_listener(result_listener), - remote_endpoint_id(remote_endpoint_id) {} -}; - -struct DisconnectFromEndpointParams { - const std::string remote_endpoint_id; - - explicit DisconnectFromEndpointParams(const std::string& remote_endpoint_id) - : remote_endpoint_id(remote_endpoint_id) {} -}; - -struct StopAllEndpointsParams { - Ptr result_listener; - - explicit StopAllEndpointsParams(Ptr result_listener) - : result_listener(result_listener) {} +// Used by Discovery in Core::RequestConnection(). +// Used by Advertising in Core::StartAdvertising(). +struct ConnectionRequestInfo { + // endpoint_info - Identifing information about this endpoint (eg. name, + // device type). + // listener - A set of callbacks notified when remote endpoints request a + // connection to this endpoint. + ByteArray endpoint_info; + ConnectionListener listener; }; } // namespace connections diff --git a/cpp/core/payload.cc b/cpp/core/payload.cc deleted file mode 100644 index cafabcee..00000000 --- a/cpp/core/payload.cc +++ /dev/null @@ -1,80 +0,0 @@ -#include "core/payload.h" - -#include -#include - -#include "platform/prng.h" - -namespace location { -namespace nearby { -namespace connections { - -////////////////////////////////// Payload ////////////////////////////////// - -Ptr Payload::fromBytes(ConstPtr bytes) { - return MakePtr(new Payload(generateId(), bytes)); -} - -Ptr Payload::fromStream(Ptr input_stream) { - return MakePtr( - new Payload(generateId(), MakeConstPtr(new Stream(input_stream)))); -} - -Ptr Payload::fromFile(const Ptr& input_file) { - return MakePtr(new Payload(generateId(), MakeConstPtr(new File(input_file)))); -} - -ConstPtr Payload::asBytes() const { return bytes_.get(); } - -ConstPtr Payload::asStream() const { return stream_.get(); } - -ConstPtr Payload::asFile() const { return file_.get(); } - -ConstPtr Payload::releaseBytes() const { return bytes_.release(); } - -std::int64_t Payload::getId() const { return id_; } - -Payload::Type::Value Payload::getType() const { return type_; } - -std::int64_t Payload::generateId() { return Prng().nextInt64(); } - -Payload::Payload(std::int64_t id, ConstPtr bytes) - : id_(id), - type_(Type::BYTES), - bytes_(std::move(bytes)), - file_(ConstPtr()), - stream_(ConstPtr()) {} - -Payload::Payload(std::int64_t id, ConstPtr file) - : id_(id), - type_(Type::FILE), - bytes_(ConstPtr()), - file_(std::move(file)), - stream_(ConstPtr()) {} - -Payload::Payload(std::int64_t id, ConstPtr stream) - : id_(id), - type_(Type::STREAM), - bytes_(ConstPtr()), - file_(ConstPtr()), - stream_(stream) {} - -//////////////////////////// Payload::File //////////////////////////////// - -Ptr Payload::File::asInputFile() const { return input_file_.get(); } - -Payload::File::File(const Ptr& input_file) - : input_file_(input_file) {} - -//////////////////////////// Payload::Stream //////////////////////////////// - -Ptr Payload::Stream::asInputStream() const { - return input_stream_.get(); -} - -Payload::Stream::Stream(Ptr input_stream) - : input_stream_(input_stream) {} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core/payload.h b/cpp/core/payload.h index 5dd3436f..fa30cbdb 100644 --- a/cpp/core/payload.h +++ b/cpp/core/payload.h @@ -2,81 +2,90 @@ #define CORE_PAYLOAD_H_ #include +#include +#include +#include -#include "platform/api/input_file.h" -#include "platform/api/input_stream.h" -#include "platform/byte_array.h" -#include "platform/ptr.h" +#include "platform/base/byte_array.h" +#include "platform/base/input_stream.h" +#include "platform/base/payload_id.h" +#include "platform/base/prng.h" +#include "platform/public/file.h" +#include "absl/types/variant.h" namespace location { namespace nearby { namespace connections { +// Payload is default-constructible, and moveable, but not copyable container +// that holds at most one instance of one of: +// ByteArray, InputStream, or InputFile. class Payload { public: - struct Type { - enum Value { UNKNOWN = 0, BYTES = 1, FILE = 2, STREAM = 3 }; - }; + using Id = PayloadId; + // Order of types in variant, and values in Type enum is important. + // Enum values must match respective variant types. + using Content = absl::variant, InputFile>; + enum class Type { kUnknown = 0, kBytes = 1, kStream = 2, kFile = 3 }; - class Stream { - public: - Ptr asInputStream() const; + Payload(Payload&& other) = default; + ~Payload() = default; + Payload& operator=(Payload&& other) = default; - private: - template - friend class InternalPayloadFactory; - friend class Payload; + // Default (invalid) payload. + Payload() : content_(absl::monostate()) {} - explicit Stream(Ptr input_stream); - ScopedPtr > input_stream_; - }; + // Constructors for outgoing payloads. + explicit Payload(ByteArray&& bytes) : content_(std::move(bytes)) {} + explicit Payload(const ByteArray& bytes) : content_(bytes) {} + explicit Payload(std::function stream) + : content_(std::move(stream)) {} - class File { - public: - Ptr asInputFile() const; + // Constructors for incoming payloads. + Payload(Id id, ByteArray&& bytes) : content_(std::move(bytes)), id_(id) {} + Payload(Id id, const ByteArray& bytes) : content_(bytes), id_(id) {} + Payload(Id id, std::function stream) + : content_(std::move(stream)), id_(id) {} - private: - template - friend class InternalPayloadFactory; - friend class Payload; + // Constructor for incoming and outgoing file payloads. + Payload(Id id, InputFile file) : content_(std::move(file)), id_(id) {} - explicit File(const Ptr& input_file); - ScopedPtr > input_file_; - }; + // Returns ByteArray payload, if it has been defined, or empty ByteArray. + const ByteArray& AsBytes() const& { + static const ByteArray empty; // NOLINT: function-level static is OK. + auto* result = absl::get_if(&content_); + return result ? *result : empty; + } + ByteArray&& AsBytes() && { + auto* result = absl::get_if(&content_); + return result ? std::move(*result) : std::move(ByteArray()); + } + // Returns InputStream* payload, if it has been defined, or nullptr. + InputStream* AsStream() { + auto* result = absl::get_if>(&content_); + return result ? &(*result)() : nullptr; + } + // Returns InputFile* payload, if it has been defined, or nullptr. + InputFile* AsFile() { return absl::get_if(&content_); } - static Ptr fromBytes(ConstPtr bytes); - static Ptr fromStream(Ptr input_stream); - static Ptr fromFile(const Ptr& input_file); + // Returns Payload unique ID. + Id GetId() const { return id_; } - ConstPtr asBytes() const; - ConstPtr asStream() const; - ConstPtr asFile() const; + // Returns Payload type. + Type GetType() const { return type_; } - // For when clients of this class want to assume ownership of the - // ConstPtr that represents a BYTES Payload. - ConstPtr releaseBytes() const; - - std::int64_t getId() const; - Type::Value getType() const; + // Generate Payload Id; to be passed to outgoing file constructor. + static Id GenerateId() { return Prng().NextInt64(); } private: - template - friend class InternalPayloadFactory; + Type FindType(const Content& content) const { + return static_cast(content_.index()); + } - static std::int64_t generateId(); - - Payload(std::int64_t id, ConstPtr bytes); - Payload(std::int64_t id, ConstPtr stream); - Payload(std::int64_t id, ConstPtr file); - - std::int64_t id_; - Type::Value type_; - // This field is mutable because of releaseBytes(), which is just a physically - // non-const operation that doesn't alter the conceptual const-ness of the - // Payload object. - mutable ScopedPtr > bytes_; - ScopedPtr > file_; - ScopedPtr > stream_; + Content content_; + Id id_{GenerateId()}; + Type type_{FindType(content_)}; }; } // namespace connections diff --git a/cpp/core_v2/payload_test.cc b/cpp/core/payload_test.cc similarity index 93% rename from cpp/core_v2/payload_test.cc rename to cpp/core/payload_test.cc index 9293194d..d6bfd3ea 100644 --- a/cpp/core_v2/payload_test.cc +++ b/cpp/core/payload_test.cc @@ -1,12 +1,12 @@ -#include "core_v2/payload.h" +#include "core/payload.h" #include #include -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/input_stream.h" -#include "platform_v2/public/file.h" -#include "platform_v2/public/pipe.h" +#include "platform/base/byte_array.h" +#include "platform/base/input_stream.h" +#include "platform/public/file.h" +#include "platform/public/pipe.h" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/cpp/core/status.h b/cpp/core/status.h index ea0de7b6..9cbc5d0a 100644 --- a/cpp/core/status.h +++ b/cpp/core/status.h @@ -5,24 +5,41 @@ namespace location { namespace nearby { namespace connections { +// Protocol operation result: kSuccess, if operation was successful; +// descriptive error code otherwise. struct Status { + // Status is a struct, so it is possible to pass some context about failure, + // by adding extra fields to it when necessary, and not change any of the + // method signatures. enum Value { - SUCCESS, - ERROR, - OUT_OF_ORDER_API_CALL, - ALREADY_HAVE_ACTIVE_STRATEGY, - ALREADY_ADVERTISING, - ALREADY_DISCOVERING, - ENDPOINT_IO_ERROR, - ENDPOINT_UNKNOWN, - CONNECTION_REJECTED, - ALREADY_CONNECTED_TO_ENDPOINT, - NOT_CONNECTED_TO_ENDPOINT, - BLUETOOTH_ERROR, - PAYLOAD_UNKNOWN, + kSuccess, + kError, + kOutOfOrderApiCall, + kAlreadyHaveActiveStrategy, + kAlreadyAdvertising, + kAlreadyDiscovering, + kEndpointIoError, + kEndpointUnknown, + kConnectionRejected, + kAlreadyConnectedToEndpoint, + kNotConnectedToEndpoint, + kBluetoothError, + kBleError, + kWifiLanError, + kPayloadUnknown, }; + Value value {kError}; + bool Ok() const { return value == kSuccess; } }; +inline bool operator==(const Status& a, const Status& b) { + return a.value == b.value; +} + +inline bool operator!=(const Status& a, const Status& b) { + return !(a == b); +} + } // namespace connections } // namespace nearby } // namespace location diff --git a/cpp/core_v2/status_test.cc b/cpp/core/status_test.cc similarity index 97% rename from cpp/core_v2/status_test.cc rename to cpp/core/status_test.cc index 86f37b4f..6c342c22 100644 --- a/cpp/core_v2/status_test.cc +++ b/cpp/core/status_test.cc @@ -1,4 +1,4 @@ -#include "core_v2/status.h" +#include "core/status.h" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/cpp/core/strategy.cc b/cpp/core/strategy.cc index 6101a3e2..2b2cbfaf 100644 --- a/cpp/core/strategy.cc +++ b/cpp/core/strategy.cc @@ -4,33 +4,29 @@ namespace location { namespace nearby { namespace connections { -const Strategy Strategy::kP2PCluster(Strategy::ConnectionType::P2P, - Strategy::TopologyType::M_TO_N); +const Strategy Strategy::kNone = {Strategy::ConnectionType::kNone, + Strategy::TopologyType::kUnknown}; +const Strategy Strategy::kP2pCluster{Strategy::ConnectionType::kPointToPoint, + Strategy::TopologyType::kManyToMany}; +const Strategy Strategy::kP2pStar{Strategy::ConnectionType::kPointToPoint, + Strategy::TopologyType::kOneToMany}; +const Strategy Strategy::kP2pPointToPoint{ + Strategy::ConnectionType::kPointToPoint, Strategy::TopologyType::kOneToOne}; -const Strategy Strategy::kP2PStar(Strategy::ConnectionType::P2P, - Strategy::TopologyType::ONE_TO_N); - -const Strategy Strategy::kP2PPointToPoint(Strategy::ConnectionType::P2P, - Strategy::TopologyType::ONE_TO_ONE); - -Strategy::Strategy(ConnectionType::Value connection_type, - TopologyType::Value topology_type) - : connection_type(connection_type), topology_type(topology_type) {} - -Strategy::Strategy(const Strategy& that) - : connection_type(that.connection_type), - topology_type(that.topology_type) {} - -bool Strategy::isValid() const { - return kP2PStar == *this || kP2PCluster == *this || kP2PPointToPoint == *this; +bool Strategy::IsNone() const { + return *this == kNone; } -std::string Strategy::getName() const { - if (Strategy::kP2PCluster == *this) { +bool Strategy::IsValid() const { + return *this == kP2pStar || *this == kP2pCluster || *this ==kP2pPointToPoint; +} + +std::string Strategy::GetName() const { + if (*this == Strategy::kP2pCluster) { return "P2P_CLUSTER"; - } else if (Strategy::kP2PStar == *this) { + } else if (*this == Strategy::kP2pStar) { return "P2P_STAR"; - } else if (Strategy::kP2PPointToPoint == *this) { + } else if (*this == Strategy::kP2pPointToPoint) { return "P2P_POINT_TO_POINT"; } else { return "UNKNOWN"; @@ -38,8 +34,8 @@ std::string Strategy::getName() const { } bool operator==(const Strategy& lhs, const Strategy& rhs) { - return lhs.connection_type == rhs.connection_type && - lhs.topology_type == rhs.topology_type; + return lhs.connection_type_ == rhs.connection_type_ && + lhs.topology_type_ == rhs.topology_type_; } bool operator!=(const Strategy& lhs, const Strategy& rhs) { diff --git a/cpp/core/strategy.h b/cpp/core/strategy.h index 2cd1dacd..2115bc44 100644 --- a/cpp/core/strategy.h +++ b/cpp/core/strategy.h @@ -1,39 +1,58 @@ #ifndef CORE_STRATEGY_H_ #define CORE_STRATEGY_H_ -#include "platform/port/string.h" +#include namespace location { namespace nearby { namespace connections { -struct Strategy { +// Defines a copyable, comparable connection strategy type. +// It is one of: kP2pCluster, kP2pStar, kP2pPointToPoint. +class Strategy { public: - static const Strategy kP2PCluster; - static const Strategy kP2PStar; - static const Strategy kP2PPointToPoint; + static const Strategy kNone; + static const Strategy kP2pCluster; + static const Strategy kP2pStar; + static const Strategy kP2pPointToPoint; - Strategy(const Strategy& that); + constexpr Strategy() : Strategy(kNone) {} - bool isValid() const; - std::string getName() const; + constexpr Strategy(const Strategy& other) + : connection_type_(other.connection_type_), + topology_type_(other.topology_type_) {} + + // Returns true, if strategy is kNone, false otherwise. + bool IsNone() const; + // Returns true, if a strategy is one of the supported strategies, + // false otherwise. + bool IsValid() const; + // Returns a string representing given strategy, for every valid strategy. + std::string GetName() const; + // Undefine strategy. + void Clear() { + *this = kNone; + } friend bool operator==(const Strategy& lhs, const Strategy& rhs); friend bool operator!=(const Strategy& lhs, const Strategy& rhs); private: - struct ConnectionType { - enum Value { P2P = 1 }; + enum class ConnectionType { + kNone = 0, + kPointToPoint = 1, }; - struct TopologyType { - enum Value { ONE_TO_ONE = 1, ONE_TO_N = 2, M_TO_N = 3 }; + enum class TopologyType { + kUnknown = 0, + kOneToOne = 1, + kOneToMany = 2, + kManyToMany = 3, }; + constexpr Strategy(ConnectionType connection_type, TopologyType topology_type) + : connection_type_(connection_type), topology_type_(topology_type) {} - const ConnectionType::Value connection_type; - const TopologyType::Value topology_type; - - Strategy(ConnectionType::Value connection_type, - TopologyType::Value topology_type); + ConnectionType connection_type_; + TopologyType topology_type_; }; } // namespace connections diff --git a/cpp/core_v2/strategy_test.cc b/cpp/core/strategy_test.cc similarity index 97% rename from cpp/core_v2/strategy_test.cc rename to cpp/core/strategy_test.cc index 6b1565e3..f0952f7d 100644 --- a/cpp/core_v2/strategy_test.cc +++ b/cpp/core/strategy_test.cc @@ -1,4 +1,4 @@ -#include "core_v2/strategy.h" +#include "core/strategy.h" #include "gtest/gtest.h" diff --git a/cpp/core_v2/BUILD b/cpp/core_v2/BUILD deleted file mode 100644 index 993686cc..00000000 --- a/cpp/core_v2/BUILD +++ /dev/null @@ -1,75 +0,0 @@ -cc_library( - name = "core_v2", - srcs = [ - "core.cc", - ], - hdrs = [ - "core.h", - ], - visibility = ["//visibility:private"], - deps = [ - ":core_types", - "//core_v2/internal", - "//platform_v2/public:comm", - "//platform_v2/public:logging", - "//platform_v2/public:types", - "//absl/strings", - "//absl/time", - "//absl/types:span", - ], -) - -cc_library( - name = "core_types", - srcs = [ - "strategy.cc", - ], - hdrs = [ - "listeners.h", - "options.h", - "params.h", - "payload.h", - "status.h", - "strategy.h", - ], - visibility = [ - "//core_v2:__subpackages__", - ], - deps = [ - "//platform_v2/base", - "//platform_v2/public:comm", - "//platform_v2/public:logging", - "//platform_v2/public:types", - "//proto:connections_enums_portable_proto", - "//absl/strings", - "//absl/types:variant", - ], -) - -cc_test( - name = "core_v2_test", - size = "small", - srcs = [ - "core_test.cc", - "listeners_test.cc", - "payload_test.cc", - "status_test.cc", - "strategy_test.cc", - ], - shard_count = 16, - deps = [ - ":core_types", - ":core_v2", - "//core_v2/internal", - "//core_v2/internal:internal_test", - "//platform_v2/base", - "//platform_v2/impl/g3", # build_cleaner: keep - "//platform_v2/public:comm", - "//platform_v2/public:logging", - "//platform_v2/public:types", - "//testing/base/public:gunit_main", - "//absl/strings", - "//absl/time", - "//absl/types:variant", - ], -) diff --git a/cpp/core_v2/core.cc b/cpp/core_v2/core.cc deleted file mode 100644 index 3b410f48..00000000 --- a/cpp/core_v2/core.cc +++ /dev/null @@ -1,110 +0,0 @@ -#include "core_v2/core.h" - -#include -#include - -#include "core_v2/options.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/logging.h" -#include "absl/time/clock.h" - -namespace location { -namespace nearby { -namespace connections { - -constexpr absl::Duration Core::kWaitForDisconnect; - -Core::~Core() { - CountDownLatch latch(1); - router_.ClientDisconnecting( - &client_, { - .result_cb = [&latch](Status) { latch.CountDown(); }, - }); - if (!latch.Await(kWaitForDisconnect).result()) { - NEARBY_LOG(FATAL, "Unable to shutdown"); - } -} - -void Core::StartAdvertising(absl::string_view service_id, - ConnectionOptions options, - ConnectionRequestInfo info, - ResultCallback callback) { - assert(!service_id.empty()); - assert(options.strategy.IsValid()); - - router_.StartAdvertising(&client_, service_id, options, info, callback); -} - -void Core::StopAdvertising(const ResultCallback callback) { - router_.StopAdvertising(&client_, callback); -} - -void Core::StartDiscovery(absl::string_view service_id, - ConnectionOptions options, DiscoveryListener listener, - ResultCallback callback) { - assert(!service_id.empty()); - assert(options.strategy.IsValid()); - - router_.StartDiscovery(&client_, service_id, options, listener, callback); -} - -void Core::StopDiscovery(ResultCallback callback) { - router_.StopDiscovery(&client_, callback); -} - -void Core::RequestConnection(absl::string_view endpoint_id, - ConnectionRequestInfo info, - ConnectionOptions options, - ResultCallback callback) { - assert(!endpoint_id.empty()); - - router_.RequestConnection(&client_, endpoint_id, info, options, callback); -} - -void Core::AcceptConnection(absl::string_view endpoint_id, - PayloadListener listener, ResultCallback callback) { - assert(!endpoint_id.empty()); - - router_.AcceptConnection(&client_, endpoint_id, listener, callback); -} - -void Core::RejectConnection(absl::string_view endpoint_id, - ResultCallback callback) { - assert(!endpoint_id.empty()); - - router_.RejectConnection(&client_, endpoint_id, callback); -} - -void Core::InitiateBandwidthUpgrade(absl::string_view endpoint_id, - ResultCallback callback) { - router_.InitiateBandwidthUpgrade(&client_, endpoint_id, callback); -} - -void Core::SendPayload(absl::Span endpoint_ids, - Payload payload, ResultCallback callback) { - assert(payload.GetType() != Payload::Type::kUnknown); - assert(!endpoint_ids.empty()); - - router_.SendPayload(&client_, endpoint_ids, std::move(payload), callback); -} - -void Core::CancelPayload(std::int64_t payload_id, ResultCallback callback) { - assert(payload_id != 0); - - router_.CancelPayload(&client_, payload_id, callback); -} - -void Core::DisconnectFromEndpoint(absl::string_view endpoint_id, - ResultCallback callback) { - assert(!endpoint_id.empty()); - - router_.DisconnectFromEndpoint(&client_, endpoint_id, callback); -} - -void Core::StopAllEndpoints(ResultCallback callback) { - router_.StopAllEndpoints(&client_, callback); -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/core.h b/cpp/core_v2/core.h deleted file mode 100644 index 37509763..00000000 --- a/cpp/core_v2/core.h +++ /dev/null @@ -1,211 +0,0 @@ -#ifndef CORE_V2_CORE_H_ -#define CORE_V2_CORE_H_ - -#include - -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/offline_service_controller.h" -#include "core_v2/internal/service_controller.h" -#include "core_v2/internal/service_controller_router.h" -#include "core_v2/listeners.h" -#include "core_v2/options.h" -#include "core_v2/params.h" -#include "absl/strings/string_view.h" -#include "absl/types/span.h" - -namespace location { -namespace nearby { -namespace connections { - -// This class defines the API of the Nearby Connections Core library. -class Core { - public: - explicit Core(std::function factory = - []() { return new OfflineServiceController; }) - : router_(factory) {} - ~Core(); - Core(Core&&) = default; - Core& operator=(Core&&) = default; - - // Starts advertising an endpoint for a local app. - // - // service_id - An identifier to advertise your app to other endpoints. - // This can be an arbitrary string, so long as it uniquely - // identifies your service. A good default is to use your - // app's package name. - // options - The options for advertising. - // info - Connection parameters: - // > name - A human readable name for this endpoint, to appear on - // other devices. - // > listener - A callback notified when remote endpoints request a - // connection to this endpoint. - // callback - to access the status of the operation when available. - // Possible status codes include: - // Status::STATUS_OK if advertising started successfully. - // Status::STATUS_ALREADY_ADVERTISING if the app is already advertising. - // Status::STATUS_OUT_OF_ORDER_API_CALL if the app is currently - // connected to remote endpoints; call StopAllEndpoints first. - void StartAdvertising(absl::string_view service_id, ConnectionOptions options, - ConnectionRequestInfo info, ResultCallback callback); - - // Stops advertising a local endpoint. Should be called after calling - // StartAdvertising, as soon as the application no longer needs to advertise - // itself or goes inactive. Payloads can still be sent to connected - // endpoints after advertising ends. - // - // result_cb - to access the status of the operation when available. - // Possible status codes include: - // Status::STATUS_OK if none of the above errors occurred. - void StopAdvertising(ResultCallback callback); - - // Starts discovery for remote endpoints with the specified service ID. - // - // service_id - The ID for the service to be discovered, as specified in - // the corresponding call to StartAdvertising. - // listener - A callback notified when a remote endpoint is discovered. - // options - The options for discovery. - // result_cb - to access the status of the operation when available. - // Possible status codes include: - // Status::STATUS_OK if discovery started successfully. - // Status::STATUS_ALREADY_DISCOVERING if the app is already - // discovering the specified service. - // Status::STATUS_OUT_OF_ORDER_API_CALL if the app is currently - // connected to remote endpoints; call StopAllEndpoints first. - void StartDiscovery(absl::string_view service_id, ConnectionOptions options, - DiscoveryListener listener, ResultCallback callback); - - // Stops discovery for remote endpoints, after a previous call to - // StartDiscovery, when the client no longer needs to discover endpoints or - // goes inactive. Payloads can still be sent to connected endpoints after - // discovery ends. - // - // result_cb - to access the status of the operation when available. - // Possible status codes include: - // Status::STATUS_OK if none of the above errors occurred. - void StopDiscovery(ResultCallback callback); - - // Sends a request to connect to a remote endpoint. - // - // endpoint_id - The identifier for the remote endpoint to which a - // connection request will be sent. Should match the value - // provided in a call to - // DiscoveryListener::endpoint_found_cb() - // info - Connection parameters: - // > name - A human readable name for the local endpoint, to appear on - // the remote endpoint. - // > listener - A callback notified when the remote endpoint sends a - // response to the connection request. - // result_cb - to access the status of the operation when available. - // Possible status codes include: - // Status::STATUS_OK if the connection request was sent. - // Status::STATUS_ALREADY_CONNECTED_TO_ENDPOINT if the app already - // has a connection to the specified endpoint. - // Status::STATUS_RADIO_ERROR if we failed to connect because of an - // issue with Bluetooth/WiFi. - // Status::STATUS_ERROR if we failed to connect for any other reason. - void RequestConnection(absl::string_view endpoint_id, - ConnectionRequestInfo info, ConnectionOptions options, - ResultCallback callback); - - // Accepts a connection to a remote endpoint. This method must be called - // before Payloads can be exchanged with the remote endpoint. - // - // endpoint_id - The identifier for the remote endpoint. Should match the - // value provided in a call to - // ConnectionListener::onConnectionInitiated. - // listener - A callback for payloads exchanged with the remote endpoint. - // result_cb - to access the status of the operation when available. - // Possible status codes include: - // Status::STATUS_OK if the connection request was accepted. - // Status::STATUS_ALREADY_CONNECTED_TO_ENDPOINT if the app already. - // has a connection to the specified endpoint. - void AcceptConnection(absl::string_view endpoint_id, PayloadListener listener, - ResultCallback callback); - - // Rejects a connection to a remote endpoint. - // - // endpoint_id - The identifier for the remote endpoint. Should match the - // value provided in a call to - // ConnectionListener::onConnectionInitiated(). - // result_cb - to access the status of the operation when available. - // Possible status codes include: - // Status::STATUS_OK} if the connection request was rejected. - // Status::STATUS_ALREADY_CONNECTED_TO_ENDPOINT} if the app already - // has a connection to the specified endpoint. - void RejectConnection(absl::string_view endpoint_id, ResultCallback callback); - - // Sends a Payload to a remote endpoint. Payloads can only be sent to remote - // endpoints once a notice of connection acceptance has been delivered via - // ConnectionListener::onConnectionResult(). - // - // endpoint_ids - Array of remote endpoint identifiers for the to which the - // payload should be sent. - // payload - The Payload to be sent. - // result_cb - to access the status of the operation when available. - // Possible status codes include: - // Status::STATUS_OUT_OF_ORDER_API_CALL if the device has not first - // performed advertisement or discovery (to set the Strategy. - // Status::STATUS_ENDPOINT_UNKNOWN if there's no active (or pending) - // connection to the remote endpoint. - // Status::STATUS_OK if none of the above errors occurred. Note that this - // indicates that Nearby Connections will attempt to send the Payload, - // but not that the send has successfully completed yet. Errors might - // still occur during transmission (and at different times for - // different endpoints), and will be delivered via - // PayloadCallback#onPayloadTransferUpdate. - void SendPayload(absl::Span endpoint_ids, Payload payload, - ResultCallback callback); - - // Cancels a Payload currently in-flight to or from remote endpoint(s). - // - // payload_id - The identifier for the Payload to be canceled. - // result_cb - to access the status of the operation when available. - // Possible status codes include: - // Status::STATUS_OK if none of the above errors occurred. - void CancelPayload(std::int64_t payload_id, ResultCallback callback); - - // Disconnects from a remote endpoint. {@link Payload}s can no longer be sent - // to or received from the endpoint after this method is called. - // - // endpoint_id - The identifier for the remote endpoint to disconnect from. - // result_cb - to access the status of the operation when available. - // Possible status codes include: - // Status::STATUS_OK - finished successfully. - void DisconnectFromEndpoint(absl::string_view endpoint_id, - ResultCallback callback); - - // Disconnects from, and removes all traces of, all connected and/or - // discovered endpoints. This call is expected to be preceded by a call to - // StopAdvertising or StartDiscovery as needed. After calling - // StopAllEndpoints, no further operations with remote endpoints will be - // possible until a new call to one of StartAdvertising() or StartDiscovery(). - // - // result_cb - to access the status of the operation when available. - // Possible status codes include: - // Status::STATUS_OK - finished successfully. - void StopAllEndpoints(ResultCallback callback); - - // Sends a request to initiate connection bandwidth upgrade. - // - // endpoint_id - The identifier for the remote endpoint which will be - // switching to a higher connection data rate and possibly - // different wireless protocol. On success, calls - // ConnectionListener::bandwidth_changed_cb(). - // result_cb - to access the status of the operation when available. - // Possible status codes include: - // Status::STATUS_OK - finished successfully. - void InitiateBandwidthUpgrade(absl::string_view endpoint_id, - ResultCallback callback); - - private: - static constexpr absl::Duration kWaitForDisconnect = absl::Milliseconds(5000); - - ClientProxy client_; - ServiceControllerRouter router_; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_CORE_H_ diff --git a/cpp/core_v2/internal/BUILD b/cpp/core_v2/internal/BUILD deleted file mode 100644 index 565a6d85..00000000 --- a/cpp/core_v2/internal/BUILD +++ /dev/null @@ -1,164 +0,0 @@ -cc_library( - name = "internal", - srcs = [ - "base_endpoint_channel.cc", - "base_pcp_handler.cc", - "ble_advertisement.cc", - "ble_endpoint_channel.cc", - "bluetooth_device_name.cc", - "bluetooth_endpoint_channel.cc", - "bwu_manager.cc", - "client_proxy.cc", - "encryption_runner.cc", - "endpoint_channel_manager.cc", - "endpoint_manager.cc", - "internal_payload.cc", - "internal_payload_factory.cc", - "offline_frames.cc", - "offline_service_controller.cc", - "p2p_cluster_pcp_handler.cc", - "p2p_point_to_point_pcp_handler.cc", - "p2p_star_pcp_handler.cc", - "payload_manager.cc", - "pcp_manager.cc", - "service_controller_router.cc", - "webrtc_bwu_handler.cc", - "webrtc_endpoint_channel.cc", - "wifi_lan_endpoint_channel.cc", - "wifi_lan_service_info.cc", - ], - hdrs = [ - "base_bwu_handler.h", - "base_endpoint_channel.h", - "base_pcp_handler.h", - "ble_advertisement.h", - "ble_endpoint_channel.h", - "bluetooth_device_name.h", - "bluetooth_endpoint_channel.h", - "bwu_handler.h", - "bwu_manager.h", - "client_proxy.h", - "encryption_runner.h", - "endpoint_channel.h", - "endpoint_channel_manager.h", - "endpoint_manager.h", - "internal_payload.h", - "internal_payload_factory.h", - "offline_frames.h", - "offline_service_controller.h", - "p2p_cluster_pcp_handler.h", - "p2p_point_to_point_pcp_handler.h", - "p2p_star_pcp_handler.h", - "payload_manager.h", - "pcp.h", - "pcp_handler.h", - "pcp_manager.h", - "service_controller.h", - "service_controller_router.h", - "webrtc_bwu_handler.h", - "webrtc_endpoint_channel.h", - "wifi_lan_endpoint_channel.h", - "wifi_lan_service_info.h", - ], - visibility = [ - "//core_v2:__pkg__", - ], - deps = [ - "//core/internal:message_lite", - "//core_v2:core_types", - "//core_v2/internal/mediums", - "//core_v2/internal/mediums:utils", - "//core_v2/internal/mediums/webrtc", - "//proto/connections:offline_wire_formats_portable_proto", - "//platform_v2/base", - "//platform_v2/base:util", - "//platform_v2/public:comm", - "//platform_v2/public:logging", - "//platform_v2/public:types", - "//proto:connections_enums_portable_proto", - "//securegcm:ukey2", - "//absl/base:core_headers", - "//absl/container:btree", - "//absl/container:flat_hash_map", - "//absl/container:flat_hash_set", - "//absl/functional:bind_front", - "//absl/memory", - "//absl/strings", - "//absl/time", - "//absl/types:span", - ], -) - -cc_library( - name = "internal_test", - testonly = True, - srcs = [ - "offline_simulation_user.cc", - "simulation_user.cc", - ], - hdrs = [ - "mock_service_controller.h", - "offline_simulation_user.h", - "simulation_user.h", - ], - visibility = [ - "//core_v2:__subpackages__", - ], - deps = [ - ":internal", - "//core_v2:core_types", - "//platform_v2/base", - "//platform_v2/base:test_util", - "//platform_v2/public:types", - "//testing/base/public:gunit", - "//absl/functional:bind_front", - "//absl/strings", - ], -) - -cc_test( - name = "core_v2_internal_test", - size = "small", - timeout = "moderate", - srcs = [ - "base_endpoint_channel_test.cc", - "base_pcp_handler_test.cc", - "ble_advertisement_test.cc", - "bluetooth_device_name_test.cc", - "bwu_manager_test.cc", - "client_proxy_test.cc", - "encryption_runner_test.cc", - "endpoint_channel_manager_test.cc", - "endpoint_manager_test.cc", - "internal_payload_factory_test.cc", - "offline_frames_test.cc", - "offline_service_controller_test.cc", - "p2p_cluster_pcp_handler_test.cc", - "payload_manager_test.cc", - "pcp_manager_test.cc", - "service_controller_router_test.cc", - "wifi_lan_service_info_test.cc", - ], - shard_count = 16, - deps = [ - ":internal", - ":internal_test", - "//core_v2:core_types", - "//core_v2/internal/mediums", - "//proto/connections:offline_wire_formats_portable_proto", - "//platform_v2/base", - "//platform_v2/base:test_util", - "//platform_v2/impl/g3", # build_cleaner: keep - "//platform_v2/public:logging", - "//platform_v2/public:types", - "//proto:connections_enums_portable_proto", - "//securegcm:ukey2", - "//testing/base/public:gunit", - "//testing/base/public:gunit_main", - "//absl/container:flat_hash_set", - "//absl/strings", - "//absl/synchronization", - "//absl/time", - "//absl/types:span", - ], -) diff --git a/cpp/core_v2/internal/base_endpoint_channel.cc b/cpp/core_v2/internal/base_endpoint_channel.cc deleted file mode 100644 index b90c19cf..00000000 --- a/cpp/core_v2/internal/base_endpoint_channel.cc +++ /dev/null @@ -1,293 +0,0 @@ -#include "core_v2/internal/base_endpoint_channel.h" - -#include - -#include "core_v2/internal/offline_frames.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/exception.h" -#include "platform_v2/public/logging.h" -#include "platform_v2/public/mutex.h" -#include "platform_v2/public/mutex_lock.h" -#include "proto/connections_enums.pb.h" -#include "absl/strings/escaping.h" -#include "absl/strings/str_cat.h" - -namespace location { -namespace nearby { -namespace connections { - -namespace { - -std::int32_t BytesToInt(const ByteArray& bytes) { - const char* int_bytes = bytes.data(); - - std::int32_t result = 0; - result |= (static_cast(int_bytes[0]) & 0x0FF) << 24; - result |= (static_cast(int_bytes[1]) & 0x0FF) << 16; - result |= (static_cast(int_bytes[2]) & 0x0FF) << 8; - result |= (static_cast(int_bytes[3]) & 0x0FF); - - return result; -} - -ByteArray IntToBytes(std::int32_t value) { - char int_bytes[sizeof(std::int32_t)]; - int_bytes[0] = static_cast((value >> 24) & 0x0FF); - int_bytes[1] = static_cast((value >> 16) & 0x0FF); - int_bytes[2] = static_cast((value >> 8) & 0x0FF); - int_bytes[3] = static_cast((value)&0x0FF); - - return ByteArray(int_bytes, sizeof(int_bytes)); -} - -ExceptionOr ReadExactly(InputStream* reader, std::int64_t size) { - ByteArray buffer(size); - std::int64_t current_pos = 0; - - while (current_pos < size) { - ExceptionOr read_bytes = reader->Read(size - current_pos); - if (!read_bytes.ok()) { - return read_bytes; - } - ByteArray result = read_bytes.result(); - - if (result.Empty()) { - return ExceptionOr(Exception::kIo); - } - - buffer.CopyAt(current_pos, result); - current_pos += result.size(); - } - - return ExceptionOr(std::move(buffer)); -} - -ExceptionOr ReadInt(InputStream* reader) { - ExceptionOr read_bytes = ReadExactly(reader, sizeof(std::int32_t)); - if (!read_bytes.ok()) { - return ExceptionOr(read_bytes.exception()); - } - return ExceptionOr(BytesToInt(std::move(read_bytes.result()))); -} - -Exception WriteInt(OutputStream* writer, std::int32_t value) { - return writer->Write(IntToBytes(value)); -} - -} // namespace - -BaseEndpointChannel::BaseEndpointChannel(const std::string& channel_name, - InputStream* reader, - OutputStream* writer) - : channel_name_(channel_name), reader_(reader), writer_(writer) {} - -ExceptionOr BaseEndpointChannel::Read() { - ByteArray result; - { - MutexLock lock(&reader_mutex_); - - ExceptionOr read_int = ReadInt(reader_); - if (!read_int.ok()) { - return ExceptionOr(read_int.exception()); - } - - if (read_int.result() < 0 || read_int.result() > kMaxAllowedReadBytes) { - return ExceptionOr(Exception::kIo); - } - - ExceptionOr read_bytes = ReadExactly(reader_, read_int.result()); - if (!read_bytes.ok()) { - return read_bytes; - } - result = std::move(read_bytes.result()); - } - - { - MutexLock crypto_lock(&crypto_mutex_); - if (IsEncryptionEnabledLocked()) { - // If encryption is enabled, decode the message. - std::string input(std::move(result)); - std::unique_ptr decrypted_data = - crypto_context_->DecodeMessageFromPeer(input); - if (decrypted_data) { - result = ByteArray(std::move(*decrypted_data)); - } else { - // It could be a protocol race, where remote party sends a KEEP_ALIVE - // before encryption is setup on their side, and we receive it after - // we switched to encryption mode. - // In this case, we verify that message is indeed a valid KEEP_ALIVE, - // and let it through if it is, otherwise message is erased. - // TODO(apolyudov): verify this happens at most once per session. - result = {}; - auto parsed = parser::FromBytes(ByteArray(input)); - if (parsed.ok() && - parser::GetFrameType(parsed.result()) == V1Frame::KEEP_ALIVE) { - result = ByteArray(input); - } - } - if (result.Empty()) { - return ExceptionOr(Exception::kInvalidProtocolBuffer); - } - } - } - - { - MutexLock lock(&last_read_mutex_); - last_read_timestamp_ = SystemClock::ElapsedRealtime(); - } - return ExceptionOr(result); -} - -Exception BaseEndpointChannel::Write(const ByteArray& data) { - { - MutexLock pause_lock(&is_paused_mutex_); - if (is_paused_) { - BlockUntilUnpaused(); - } - } - - ByteArray encrypted_data; - const ByteArray* data_to_write = &data; - { - MutexLock crypto_lock(&crypto_mutex_); - if (IsEncryptionEnabledLocked()) { - // If encryption is enabled, encode the message. - std::unique_ptr encrypted = - crypto_context_->EncodeMessageToPeer(std::string(data)); - if (!encrypted) return {Exception::kIo}; - encrypted_data = ByteArray(std::move(*encrypted)); - data_to_write = &encrypted_data; - } - } - - { - MutexLock lock(&writer_mutex_); - Exception write_exception = - WriteInt(writer_, static_cast(data_to_write->size())); - if (write_exception.Raised()) { - return write_exception; - } - write_exception = writer_->Write(*data_to_write); - if (write_exception.Raised()) { - return write_exception; - } - Exception flush_exception = writer_->Flush(); - if (flush_exception.Raised()) { - return flush_exception; - } - } - - return {Exception::kSuccess}; -} - -void BaseEndpointChannel::Close() { - { - // In case channel is paused, resume it first thing. - MutexLock lock(&is_paused_mutex_); - UnblockPausedWriter(); - } - CloseIo(); - CloseImpl(); -} - -void BaseEndpointChannel::CloseIo() { - // Keep this method dedicated to reader and writer handling an nothing else. - { - // Do not take reader_mutex_ here: read may be in progress, and it will - // deadlock. Calling Close() with Read() in progress will terminate the - // IO and Read() will proceed normally (with Exception::kIo). - Exception exception = reader_->Close(); - if (!exception.Ok()) { - // Add logging. - } - } - { - // Do not take writer_mutex_ here: write may be in progress, and it will - // deadlock. Calling Close() with Write() in progress will terminate the - // IO and Write() will proceed normally (with Exception::kIo). - Exception exception = writer_->Close(); - if (!exception.Ok()) { - // Add logging. - } - } -} - -void BaseEndpointChannel::Close( - proto::connections::DisconnectionReason reason) { - Close(); -} - -std::string BaseEndpointChannel::GetType() const { - MutexLock crypto_lock(&crypto_mutex_); - std::string subtype = IsEncryptionEnabledLocked() ? "ENCRYPTED_" : ""; - - switch (GetMedium()) { - case proto::connections::Medium::BLUETOOTH: - return absl::StrCat(subtype, "BLUETOOTH"); - case proto::connections::Medium::BLE: - return absl::StrCat(subtype, "BLE"); - case proto::connections::Medium::MDNS: - return absl::StrCat(subtype, "MDNS"); - case proto::connections::Medium::WIFI_HOTSPOT: - return absl::StrCat(subtype, "WIFI_HOTSPOT"); - case proto::connections::Medium::WIFI_LAN: - return absl::StrCat(subtype, "WIFI_LAN"); - default: - return "UNKNOWN"; - } -} - -std::string BaseEndpointChannel::GetName() const { return channel_name_; } - -void BaseEndpointChannel::EnableEncryption( - std::shared_ptr context) { - MutexLock crypto_lock(&crypto_mutex_); - crypto_context_ = context; -} - -bool BaseEndpointChannel::IsPaused() const { - MutexLock lock(&is_paused_mutex_); - return is_paused_; -} - -void BaseEndpointChannel::Pause() { - MutexLock lock(&is_paused_mutex_); - is_paused_ = true; -} - -void BaseEndpointChannel::Resume() { - MutexLock lock(&is_paused_mutex_); - is_paused_ = false; - is_paused_cond_.Notify(); -} - -absl::Time BaseEndpointChannel::GetLastReadTimestamp() const { - MutexLock lock(&last_read_mutex_); - return last_read_timestamp_; -} - -bool BaseEndpointChannel::IsEncryptionEnabledLocked() const { - return crypto_context_ != nullptr; -} - -void BaseEndpointChannel::BlockUntilUnpaused() { - // For more on how this works, see - // https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html - while (is_paused_) { - Exception wait_succeeded = is_paused_cond_.Wait(); - if (!wait_succeeded.Ok()) { - return; - } - } -} - -void BaseEndpointChannel::UnblockPausedWriter() { - // For more on how this works, see - // https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html - is_paused_ = false; - is_paused_cond_.Notify(); -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/base_endpoint_channel.h b/cpp/core_v2/internal/base_endpoint_channel.h deleted file mode 100644 index 347dfe2c..00000000 --- a/cpp/core_v2/internal/base_endpoint_channel.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef CORE_V2_INTERNAL_BASE_ENDPOINT_CHANNEL_H_ -#define CORE_V2_INTERNAL_BASE_ENDPOINT_CHANNEL_H_ - -#include -#include -#include - -#include "core_v2/internal/endpoint_channel.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/input_stream.h" -#include "platform_v2/base/output_stream.h" -#include "platform_v2/public/atomic_reference.h" -#include "platform_v2/public/condition_variable.h" -#include "platform_v2/public/mutex.h" -#include "platform_v2/public/system_clock.h" -#include "proto/connections_enums.pb.h" -#include "securegcm/d2d_connection_context_v1.h" -#include "absl/base/thread_annotations.h" - -namespace location { -namespace nearby { -namespace connections { - -class BaseEndpointChannel : public EndpointChannel { - public: - BaseEndpointChannel(const std::string& channel_name, InputStream* reader, - OutputStream* writer); - ~BaseEndpointChannel() override = default; - - ExceptionOr Read() - ABSL_LOCKS_EXCLUDED(reader_mutex_, crypto_mutex_, - last_read_mutex_) override; - - Exception Write(const ByteArray& data) - ABSL_LOCKS_EXCLUDED(writer_mutex_, crypto_mutex_) override; - - // Closes this EndpointChannel, without tracking the closure in analytics. - void Close() ABSL_LOCKS_EXCLUDED(is_paused_mutex_) override; - - // Closes this EndpointChannel and records the closure with the given reason. - void Close(proto::connections::DisconnectionReason reason) override; - - // Returns a one-word type descriptor for the concrete EndpointChannel - // implementation that can be used in log messages; eg: BLUETOOTH, BLE, - // WIFI. - std::string GetType() const override; - - // Returns the name of the EndpointChannel. - std::string GetName() const override; - - // Enables encryption on the EndpointChannel. - // Should be called after connection is accepted by both parties, and - // before entering data phase, where Payloads may be exchanged. - void EnableEncryption(std::shared_ptr context) override; - - // True if the EndpointChannel is currently pausing all writes. - bool IsPaused() const ABSL_LOCKS_EXCLUDED(is_paused_mutex_) override; - - // Pauses all writes on this EndpointChannel until resume() is called. - void Pause() ABSL_LOCKS_EXCLUDED(is_paused_mutex_) override; - - // Resumes any writes on this EndpointChannel that were suspended when pause() - // was called. - void Resume() ABSL_LOCKS_EXCLUDED(is_paused_mutex_) override; - - // Returns the timestamp (returned by ElapsedRealtime) of the last read from - // this endpoint, or -1 if no reads have occurred. - absl::Time GetLastReadTimestamp() const - ABSL_LOCKS_EXCLUDED(last_read_mutex_) override; - - protected: - virtual void CloseImpl() = 0; - - private: - // Used to sanity check that our frame sizes are reasonable. - static constexpr std::int32_t kMaxAllowedReadBytes = 1048576; // 1MB - - bool IsEncryptionEnabledLocked() const - ABSL_EXCLUSIVE_LOCKS_REQUIRED(crypto_mutex_); - void UnblockPausedWriter() ABSL_EXCLUSIVE_LOCKS_REQUIRED(is_paused_mutex_); - void BlockUntilUnpaused() ABSL_EXCLUSIVE_LOCKS_REQUIRED(is_paused_mutex_); - void CloseIo() ABSL_NO_THREAD_SAFETY_ANALYSIS; - - // We need a separate mutex to pritect read timestamp, because if a read - // blocks on IO, we don't want timestamp read access to block too. - mutable Mutex last_read_mutex_; - absl::Time last_read_timestamp_ ABSL_GUARDED_BY(last_read_mutex_) = - absl::InfinitePast(); - const std::string channel_name_; - - // The reader and writer are synchronized independently since we can't have - // writes waiting on reads that might potentially block forever. - Mutex reader_mutex_; - InputStream* reader_ ABSL_PT_GUARDED_BY(reader_mutex_); - - Mutex writer_mutex_; - OutputStream* writer_ ABSL_PT_GUARDED_BY(writer_mutex_); - - // An encryptor/decryptor. May be null. - mutable Mutex crypto_mutex_; - std::shared_ptr crypto_context_ - ABSL_GUARDED_BY(crypto_mutex_) ABSL_PT_GUARDED_BY(crypto_mutex_); - - mutable Mutex is_paused_mutex_; - ConditionVariable is_paused_cond_{&is_paused_mutex_}; - // If true, writes should block until this has been set to false. - bool is_paused_ ABSL_GUARDED_BY(is_paused_mutex_) = false; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_BASE_ENDPOINT_CHANNEL_H_ diff --git a/cpp/core_v2/internal/base_endpoint_channel_test.cc b/cpp/core_v2/internal/base_endpoint_channel_test.cc deleted file mode 100644 index 7a2869fc..00000000 --- a/cpp/core_v2/internal/base_endpoint_channel_test.cc +++ /dev/null @@ -1,342 +0,0 @@ -#include "core_v2/internal/base_endpoint_channel.h" - -#include - -#include "core_v2/internal/encryption_runner.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/input_stream.h" -#include "platform_v2/base/output_stream.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/logging.h" -#include "platform_v2/public/multi_thread_executor.h" -#include "platform_v2/public/pipe.h" -#include "platform_v2/public/single_thread_executor.h" -#include "proto/connections_enums.pb.h" -#include "proto/connections_enums.pb.h" -#include "securegcm/d2d_connection_context_v1.h" -#include "securegcm/ukey2_handshake.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "absl/synchronization/mutex.h" -#include "absl/time/time.h" - -namespace location { -namespace nearby { -namespace connections { -namespace { - -using ::location::nearby::proto::connections::DisconnectionReason; -using ::location::nearby::proto::connections::Medium; -using EncryptionContext = BaseEndpointChannel::EncryptionContext; - -class TestEndpointChannel : public BaseEndpointChannel { - public: - explicit TestEndpointChannel(InputStream* input, OutputStream* output) - : BaseEndpointChannel("channel", input, output) {} - - MOCK_METHOD(Medium, GetMedium, (), (const override)); - MOCK_METHOD(void, CloseImpl, (), (override)); -}; - -std::function MakeDataPump( - std::string label, InputStream* input, OutputStream* output, - std::function monitor = nullptr) { - return [label, input, output, monitor]() { - NEARBY_LOG(INFO, "streaming data thorough '%s'", label.c_str()); - while (true) { - auto read_response = input->Read(Pipe::kChunkSize); - if (!read_response.ok()) { - NEARBY_LOG(INFO, "Peer reader closed on '%s'", label.c_str()); - output->Close(); - break; - } - if (monitor) { - monitor(read_response.result()); - } - auto write_response = output->Write(read_response.result()); - if (write_response.Raised()) { - NEARBY_LOG(INFO, "Peer writer closed on '%s'", label.c_str()); - input->Close(); - break; - } - } - NEARBY_LOG(INFO, "streaming terminated on '%s'", label.c_str()); - }; -} - -std::function MakeDataMonitor(const std::string& label, - std::string* capture, - absl::Mutex* mutex) { - return [label, capture, mutex](const ByteArray& input) mutable { - std::string s = std::string(input); - { - absl::MutexLock lock(mutex); - *capture += s; - } - NEARBY_LOG(INFO, "source='%s'; message='%s'", label.c_str(), s.c_str()); - }; -} - -std::pair, - std::shared_ptr> -DoDhKeyExchange(BaseEndpointChannel* channel_a, - BaseEndpointChannel* channel_b) { - std::shared_ptr context_a; - std::shared_ptr context_b; - EncryptionRunner crypto_a; - EncryptionRunner crypto_b; - ClientProxy proxy_a; - ClientProxy proxy_b; - CountDownLatch latch(2); - crypto_a.StartClient( - &proxy_a, "endpoint_id", channel_a, - { - .on_success_cb = - [&latch, &context_a]( - const string& endpoint_id, - std::unique_ptr ukey2, - const string& auth_token, const ByteArray& raw_auth_token) { - NEARBY_LOG(INFO, "client-A side key negotiation done"); - EXPECT_TRUE(ukey2->VerifyHandshake()); - auto context = ukey2->ToConnectionContext(); - EXPECT_NE(context, nullptr); - context_a = std::move(context); - latch.CountDown(); - }, - .on_failure_cb = - [&latch](const string& endpoint_id, EndpointChannel* channel) { - NEARBY_LOG(INFO, "client-A side key negotiation failed"); - latch.CountDown(); - }, - }); - crypto_b.StartServer( - &proxy_b, "endpoint_id", channel_b, - { - .on_success_cb = - [&latch, &context_b]( - const string& endpoint_id, - std::unique_ptr ukey2, - const string& auth_token, const ByteArray& raw_auth_token) { - NEARBY_LOG(INFO, "client-B side key negotiation done"); - EXPECT_TRUE(ukey2->VerifyHandshake()); - auto context = ukey2->ToConnectionContext(); - EXPECT_NE(context, nullptr); - context_b = std::move(context); - latch.CountDown(); - }, - .on_failure_cb = - [&latch](const string& endpoint_id, EndpointChannel* channel) { - NEARBY_LOG(INFO, "client-B side key negotiation failed"); - latch.CountDown(); - }, - }); - EXPECT_TRUE(latch.Await(absl::Milliseconds(5000)).result()); - return std::make_pair(std::move(context_a), std::move(context_b)); -} - -TEST(BaseEndpointChannelTest, ConstructorDestructorWorks) { - Pipe pipe; - InputStream& input_stream = pipe.GetInputStream(); - OutputStream& output_stream = pipe.GetOutputStream(); - - TestEndpointChannel test_channel(&input_stream, &output_stream); -} - -TEST(BaseEndpointChannelTest, ReadWrite) { - // Direct not-encrypted IO. - Pipe pipe_a; // channel_a writes to pipe_a, reads from pipe_b. - Pipe pipe_b; // channel_b writes to pipe_b, reads from pipe_a. - TestEndpointChannel channel_a(&pipe_b.GetInputStream(), - &pipe_a.GetOutputStream()); - TestEndpointChannel channel_b(&pipe_a.GetInputStream(), - &pipe_b.GetOutputStream()); - ByteArray tx_message{"data message"}; - channel_a.Write(tx_message); - ByteArray rx_message = std::move(channel_b.Read().result()); - EXPECT_EQ(rx_message, tx_message); -} - -TEST(BaseEndpointChannelTest, NotEncryptedReadWriteCanBeIntercepted) { - // Not encrypted IO; MITM scenario. - - // Setup test communication environment. - absl::Mutex mutex; - std::string capture_a; - std::string capture_b; - Pipe client_a; // Channel "a" writes to client "a", reads from server "a". - Pipe client_b; // Channel "b" writes to client "b", reads from server "b". - Pipe server_a; // Data pump "a" reads from client "a", writes to server "b". - Pipe server_b; // Data pump "b" reads from client "b", writes to server "a". - TestEndpointChannel channel_a(&server_a.GetInputStream(), - &client_a.GetOutputStream()); - TestEndpointChannel channel_b(&server_b.GetInputStream(), - &client_b.GetOutputStream()); - - ON_CALL(channel_a, GetMedium).WillByDefault([]() { return Medium::BLE; }); - ON_CALL(channel_b, GetMedium).WillByDefault([]() { return Medium::BLE; }); - - MultiThreadExecutor executor(2); - executor.Execute(MakeDataPump( - "pump_a", &client_a.GetInputStream(), &server_b.GetOutputStream(), - MakeDataMonitor("monitor_a", &capture_a, &mutex))); - executor.Execute(MakeDataPump( - "pump_b", &client_b.GetInputStream(), &server_a.GetOutputStream(), - MakeDataMonitor("monitor_b", &capture_b, &mutex))); - - EXPECT_EQ(channel_a.GetType(), "BLE"); - EXPECT_EQ(channel_b.GetType(), "BLE"); - - // Start data transfer - ByteArray tx_message{"data message"}; - channel_a.Write(tx_message); - ByteArray rx_message = std::move(channel_b.Read().result()); - - // Verify expectations. - EXPECT_EQ(rx_message, tx_message); - { - absl::MutexLock lock(&mutex); - std::string message{tx_message}; - EXPECT_TRUE(capture_a.find(message) != std::string::npos || - capture_b.find(message) != std::string::npos); - } - - // Shutdown test environment. - channel_a.Close(DisconnectionReason::LOCAL_DISCONNECTION); - channel_b.Close(DisconnectionReason::REMOTE_DISCONNECTION); -} - -TEST(BaseEndpointChannelTest, EncryptedReadWriteCanNotBeIntercepted) { - // Encrypted IO; MITM scenario. - - // Setup test communication environment. - absl::Mutex mutex; - std::string capture_a; - std::string capture_b; - Pipe client_a; // Channel "a" writes to client "a", reads from server "a". - Pipe client_b; // Channel "b" writes to client "b", reads from server "b". - Pipe server_a; // Data pump "a" reads from client "a", writes to server "b". - Pipe server_b; // Data pump "b" reads from client "b", writes to server "a". - TestEndpointChannel channel_a(&server_a.GetInputStream(), - &client_a.GetOutputStream()); - TestEndpointChannel channel_b(&server_b.GetInputStream(), - &client_b.GetOutputStream()); - - ON_CALL(channel_a, GetMedium).WillByDefault([]() { - return Medium::BLUETOOTH; - }); - ON_CALL(channel_b, GetMedium).WillByDefault([]() { - return Medium::BLUETOOTH; - }); - - MultiThreadExecutor executor(2); - executor.Execute(MakeDataPump( - "pump_a", &client_a.GetInputStream(), &server_b.GetOutputStream(), - MakeDataMonitor("monitor_a", &capture_a, &mutex))); - executor.Execute(MakeDataPump( - "pump_b", &client_b.GetInputStream(), &server_a.GetOutputStream(), - MakeDataMonitor("monitor_b", &capture_b, &mutex))); - - // Run DH key exchange; setup encryption contexts for channels. - auto [context_a, context_b] = DoDhKeyExchange(&channel_a, &channel_b); - ASSERT_NE(context_a, nullptr); - ASSERT_NE(context_b, nullptr); - channel_a.EnableEncryption(context_a); - channel_b.EnableEncryption(context_b); - - EXPECT_EQ(channel_a.GetType(), "ENCRYPTED_BLUETOOTH"); - EXPECT_EQ(channel_b.GetType(), "ENCRYPTED_BLUETOOTH"); - - // Start data transfer - ByteArray tx_message{"data message"}; - channel_a.Write(tx_message); - ByteArray rx_message = std::move(channel_b.Read().result()); - - // Verify expectations. - EXPECT_EQ(rx_message, tx_message); - { - absl::MutexLock lock(&mutex); - std::string message{tx_message}; - EXPECT_TRUE(capture_a.find(message) == std::string::npos && - capture_b.find(message) == std::string::npos); - } - - // Shutdown test environment. - channel_a.Close(DisconnectionReason::LOCAL_DISCONNECTION); - channel_b.Close(DisconnectionReason::REMOTE_DISCONNECTION); -} - -TEST(BaseEndpointChannelTest, CanBesuspendedAndResumed) { - // Setup test communication environment. - Pipe pipe_a; // channel_a writes to pipe_a, reads from pipe_b. - Pipe pipe_b; // channel_b writes to pipe_b, reads from pipe_a. - TestEndpointChannel channel_a(&pipe_b.GetInputStream(), - &pipe_a.GetOutputStream()); - TestEndpointChannel channel_b(&pipe_a.GetInputStream(), - &pipe_b.GetOutputStream()); - - ON_CALL(channel_a, GetMedium).WillByDefault([]() { - return Medium::WIFI_LAN; - }); - ON_CALL(channel_b, GetMedium).WillByDefault([]() { - return Medium::WIFI_LAN; - }); - - EXPECT_EQ(channel_a.GetType(), "WIFI_LAN"); - EXPECT_EQ(channel_b.GetType(), "WIFI_LAN"); - - // Start data transfer - ByteArray tx_message{"data message"}; - ByteArray more_message{"more data"}; - channel_a.Write(tx_message); - ByteArray rx_message = std::move(channel_b.Read().result()); - - // Pause and make sure reader blocks. - MultiThreadExecutor pause_resume_executor(2); - channel_a.Pause(); - pause_resume_executor.Execute([&channel_a, &more_message]() { - // Write will block until channel is resumed, or closed. - EXPECT_TRUE(channel_a.Write(more_message).Ok()); - }); - CountDownLatch latch(1); - ByteArray read_more; - pause_resume_executor.Execute([&channel_b, &read_more, &latch]() { - // Read will block until channel is resumed, or closed. - auto response = channel_b.Read(); - EXPECT_TRUE(response.ok()); - read_more = std::move(response.result()); - latch.CountDown(); - }); - absl::SleepFor(absl::Milliseconds(500)); - EXPECT_TRUE(read_more.Empty()); - - // Resume; verify that data transfer comepleted. - channel_a.Resume(); - EXPECT_TRUE(latch.Await(absl::Milliseconds(1000)).result()); - EXPECT_EQ(read_more, more_message); - - // Shutdown test environment. - channel_a.Close(DisconnectionReason::LOCAL_DISCONNECTION); - channel_b.Close(DisconnectionReason::REMOTE_DISCONNECTION); -} - -TEST(BaseEndpointChannelTest, ReadAfterInputStreamClosed) { - Pipe pipe; - InputStream& input_stream = pipe.GetInputStream(); - OutputStream& output_stream = pipe.GetOutputStream(); - - TestEndpointChannel test_channel(&input_stream, &output_stream); - - // Close the output stream before trying to read from the input. - output_stream.Close(); - - // Trying to read should fail gracefully with an IO error. - ExceptionOr read_data = test_channel.Read(); - - ASSERT_FALSE(read_data.ok()); - ASSERT_TRUE(read_data.GetException().Raised(Exception::kIo)); -} - -} // namespace -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/base_pcp_handler.cc b/cpp/core_v2/internal/base_pcp_handler.cc deleted file mode 100644 index 1d77ca79..00000000 --- a/cpp/core_v2/internal/base_pcp_handler.cc +++ /dev/null @@ -1,1226 +0,0 @@ -#include "core_v2/internal/base_pcp_handler.h" - -#include -#include -#include -#include -#include - -#include "core_v2/internal/offline_frames.h" -#include "core_v2/internal/pcp_handler.h" -#include "core_v2/options.h" -#include "platform_v2/base/bluetooth_utils.h" -#include "platform_v2/public/logging.h" -#include "platform_v2/public/system_clock.h" -#include "securegcm/d2d_connection_context_v1.h" -#include "securegcm/ukey2_handshake.h" -#include "absl/container/flat_hash_set.h" -#include "absl/strings/escaping.h" -#include "absl/types/span.h" - -namespace location { -namespace nearby { -namespace connections { - -using ::location::nearby::proto::connections::Medium; -using ::securegcm::UKey2Handshake; - -constexpr absl::Duration BasePcpHandler::kConnectionRequestReadTimeout; -constexpr absl::Duration BasePcpHandler::kRejectedConnectionCloseDelay; - -BasePcpHandler::BasePcpHandler(Mediums* mediums, - EndpointManager* endpoint_manager, - EndpointChannelManager* channel_manager, - BwuManager* bwu_manager, Pcp pcp) - : mediums_(mediums), - endpoint_manager_(endpoint_manager), - channel_manager_(channel_manager), - pcp_(pcp), - bwu_manager_(bwu_manager) {} - -BasePcpHandler::~BasePcpHandler() { - NEARBY_LOGS(INFO) << "BasePcpHandler: going down; strategy=" - << strategy_.GetName() << "; handle=" << handle_; - DisconnectFromEndpointManager(); - // Stop all the ongoing Runnables (as gracefully as possible). - NEARBY_LOGS(INFO) << "BasePcpHandler: bringing down executors; strategy=" - << strategy_.GetName(); - serial_executor_.Shutdown(); - alarm_executor_.Shutdown(); - NEARBY_LOGS(INFO) << "BasePcpHandler: is down; strategy=" - << strategy_.GetName(); -} - -void BasePcpHandler::DisconnectFromEndpointManager() { - if (stop_.Set(true)) return; - NEARBY_LOGS(INFO) << "BasePcpHandler: Unregister from EPM; strategy=" - << strategy_.GetName() << "; handle=" << handle_; - // Unregister ourselves from EPM message dispatcher. - endpoint_manager_->UnregisterFrameProcessor(V1Frame::CONNECTION_RESPONSE, - handle_, true); -} - -Status BasePcpHandler::StartAdvertising(ClientProxy* client, - const std::string& service_id, - const ConnectionOptions& options, - const ConnectionRequestInfo& info) { - Future response; - ConnectionOptions advertising_options = options.CompatibleOptions(); - RunOnPcpHandlerThread([this, client, &service_id, &info, &advertising_options, - &response]() { - auto result = - StartAdvertisingImpl(client, service_id, client->GetLocalEndpointId(), - info.endpoint_info, advertising_options); - if (!result.status.Ok()) { - response.Set(result.status); - return; - } - - // Now that we've succeeded, mark the client as advertising. - advertising_options_ = advertising_options; - advertising_listener_ = info.listener; - client->StartedAdvertising(service_id, GetStrategy(), info.listener, - absl::MakeSpan(result.mediums)); - response.Set({Status::kSuccess}); - }); - return WaitForResult( - absl::StrCat("StartAdvertising(", std::string(info.endpoint_info), ")"), - client->GetClientId(), &response); -} - -void BasePcpHandler::StopAdvertising(ClientProxy* client) { - CountDownLatch latch(1); - RunOnPcpHandlerThread([this, client, &latch]() { - StopAdvertisingImpl(client); - client->StoppedAdvertising(); - advertising_options_.Clear(); - latch.CountDown(); - }); - WaitForLatch("StopAdvertising", &latch); -} - -Status BasePcpHandler::StartDiscovery(ClientProxy* client, - const std::string& service_id, - const ConnectionOptions& options, - const DiscoveryListener& listener) { - Future response; - ConnectionOptions discovery_options = options.CompatibleOptions(); - RunOnPcpHandlerThread( - [this, client, service_id, discovery_options, &listener, &response]() { - // Ask the implementation to attempt to start discovery. - auto result = StartDiscoveryImpl(client, service_id, discovery_options); - if (!result.status.Ok()) { - response.Set(result.status); - return; - } - - // Now that we've succeeded, mark the client as discovering and clear - // out any old endpoints we had discovered. - discovery_options_ = discovery_options; - discovered_endpoints_.clear(); - client->StartedDiscovery(service_id, GetStrategy(), listener, - absl::MakeSpan(result.mediums)); - response.Set({Status::kSuccess}); - }); - return WaitForResult(absl::StrCat("StartDiscovery(", service_id, ")"), - client->GetClientId(), &response); -} - -void BasePcpHandler::StopDiscovery(ClientProxy* client) { - CountDownLatch latch(1); - RunOnPcpHandlerThread([this, client, &latch]() { - StopDiscoveryImpl(client); - client->StoppedDiscovery(); - discovery_options_.Clear(); - latch.CountDown(); - }); - - WaitForLatch("StopDiscovery", &latch); -} - -void BasePcpHandler::WaitForLatch(const std::string& method_name, - CountDownLatch* latch) { - Exception await_exception = latch->Await(); - if (!await_exception.Ok()) { - if (await_exception.Raised(Exception::kTimeout)) { - NEARBY_LOG(INFO, "Blocked in %s", method_name.c_str()); - } - } -} - -Status BasePcpHandler::WaitForResult(const std::string& method_name, - std::int64_t client_id, - Future* future) { - if (!future) { - NEARBY_LOG(INFO, "No future to wait for; return with error"); - return {Status::kError}; - } - NEARBY_LOG(INFO, "waiting for future to complete"); - ExceptionOr result = future->Get(); - if (!result.ok()) { - NEARBY_LOG(INFO, "Future:[%s] completed with exception: %d", - method_name.c_str(), result.exception()); - return {Status::kError}; - } - NEARBY_LOG(INFO, "Future:[%s] completed with status: %d", method_name.c_str(), - result.result().value); - return result.result(); -} - -void BasePcpHandler::RunOnPcpHandlerThread(Runnable runnable) { - serial_executor_.Execute(std::move(runnable)); -} - -EncryptionRunner::ResultListener BasePcpHandler::GetResultListener() { - return { - .on_success_cb = - [this](const std::string& endpoint_id, - std::unique_ptr ukey2, - const std::string& auth_token, - const ByteArray& raw_auth_token) { - RunOnPcpHandlerThread([this, endpoint_id, - raw_ukey2 = ukey2.release(), auth_token, - raw_auth_token]() mutable { - OnEncryptionSuccessRunnable( - endpoint_id, std::unique_ptr(raw_ukey2), - auth_token, raw_auth_token); - }); - }, - .on_failure_cb = - [this](const std::string& endpoint_id, EndpointChannel* channel) { - RunOnPcpHandlerThread([this, endpoint_id, channel]() { - OnEncryptionFailureRunnable(endpoint_id, channel); - }); - }, - }; -} - -void BasePcpHandler::OnEncryptionSuccessRunnable( - const std::string& endpoint_id, std::unique_ptr ukey2, - const std::string& auth_token, const ByteArray& raw_auth_token) { - // Quick fail if we've been removed from pending connections while we were - // busy running UKEY2. - auto it = pending_connections_.find(endpoint_id); - if (it == pending_connections_.end()) { - NEARBY_LOG(INFO, - "Connection not found on UKEY negotination complete; id=%s", - endpoint_id.c_str()); - return; - } - - BasePcpHandler::PendingConnectionInfo& connection_info = it->second; - - if (!ukey2) { - // Fail early, if there is no crypto context. - ProcessPreConnectionResultFailure(connection_info.client, endpoint_id); - return; - } - - connection_info.SetCryptoContext(std::move(ukey2)); - NEARBY_LOG(INFO, "Register encrypted connection; wait for response; id=%s", - endpoint_id.c_str()); - - // Set ourselves up so that we receive all acceptance/rejection messages - handle_ = endpoint_manager_->RegisterFrameProcessor( - V1Frame::CONNECTION_RESPONSE, - static_cast(this)); - - // Now we register our endpoint so that we can listen for both sides to - // accept. - endpoint_manager_->RegisterEndpoint( - connection_info.client, endpoint_id, - { - .remote_endpoint_info = connection_info.remote_endpoint_info, - .authentication_token = auth_token, - .raw_authentication_token = raw_auth_token, - .is_incoming_connection = connection_info.is_incoming, - }, - connection_info.options, std::move(connection_info.channel), - connection_info.listener); - - if (connection_info.result != nullptr) { - NEARBY_LOG(INFO, "Connection established; Finalising future OK"); - connection_info.result->Set({Status::kSuccess}); - connection_info.result = nullptr; - } -} - -void BasePcpHandler::OnEncryptionFailureRunnable( - const std::string& endpoint_id, EndpointChannel* endpoint_channel) { - auto it = pending_connections_.find(endpoint_id); - if (it == pending_connections_.end()) { - NEARBY_LOG(INFO, - "Connection not found on UKEY negotination complete; id=%s", - endpoint_id.c_str()); - return; - } - - BasePcpHandler::PendingConnectionInfo& info = it->second; - // We had a bug here, caused by a race with EncryptionRunner. We now verify - // the EndpointChannel to avoid it. In a simultaneous connection, we clean - // up one of the two EndpointChannels and then update our pendingConnections - // with the winning channel's state. Closing a channel that was in the - // middle of EncryptionRunner would trigger onEncryptionFailed, and, since - // the map had already updated with the winning EndpointChannel, we closed - // it too by accident. - if (*endpoint_channel != *info.channel) { - NEARBY_LOG( - INFO, "Not destroying channel [mismatch]: passed=%s; expected=%s", - endpoint_channel->GetName().c_str(), info.channel->GetName().c_str()); - return; - } - - ProcessPreConnectionInitiationFailure(endpoint_id, info.channel.get(), - {Status::kEndpointIoError}, - info.result.get()); - info.result.reset(); -} - -Status BasePcpHandler::RequestConnection(ClientProxy* client, - const std::string& endpoint_id, - const ConnectionRequestInfo& info, - const ConnectionOptions& options) { - Future result; - RunOnPcpHandlerThread([this, client, &info, options, endpoint_id, &result]() { - absl::Time start_time = SystemClock::ElapsedRealtime(); - - // If we already have a pending connection, then we shouldn't allow any more - // outgoing connections to this endpoint. - if (pending_connections_.count(endpoint_id)) { - NEARBY_LOG(INFO, "Connection already exists: id=%s", endpoint_id.c_str()); - result.Set({Status::kAlreadyConnectedToEndpoint}); - return; - } - - // If our child class says we can't send any more outgoing connections, - // listen to them. - if (ShouldEnforceTopologyConstraints() && - !CanSendOutgoingConnection(client)) { - NEARBY_LOG(INFO, "Outgoing connection not allowed: id=%s", - endpoint_id.c_str()); - result.Set({Status::kOutOfOrderApiCall}); - return; - } - - DiscoveredEndpoint* endpoint = GetDiscoveredEndpoint(endpoint_id); - if (endpoint == nullptr) { - NEARBY_LOG(INFO, "Discovered endpoint not found: id=%s", - endpoint_id.c_str()); - result.Set({Status::kEndpointUnknown}); - return; - } - - auto remote_bluetooth_mac_address = - BluetoothUtils::ToString(options.remote_bluetooth_mac_address); - if (!remote_bluetooth_mac_address.empty()) { - if (AppendRemoteBluetoothMacAddressEndpoint(endpoint_id, - remote_bluetooth_mac_address)) - NEARBY_LOGS(INFO) << "Appended remote Bluetooth MAC Address endpoint " - << "[" << remote_bluetooth_mac_address << "]"; - } - - if (AppendWebRTCEndpoint(endpoint_id)) - NEARBY_LOGS(INFO) << "Appended Web RTC endpoint."; - - auto discovered_endpoints = GetDiscoveredEndpoints(endpoint_id); - std::unique_ptr channel; - ConnectImplResult connect_impl_result; - - for (auto connect_endpoint : discovered_endpoints) { - connect_impl_result = ConnectImpl(client, connect_endpoint); - if (connect_impl_result.status.Ok()) { - channel = std::move(connect_impl_result.endpoint_channel); - break; - } - } - - if (channel == nullptr) { - NEARBY_LOG(INFO, "Endpoint channel not available: id=%s", - endpoint_id.c_str()); - ProcessPreConnectionInitiationFailure( - endpoint_id, channel.get(), connect_impl_result.status, &result); - return; - } - - NEARBY_LOG(INFO, "Sending connection request: id=%s", endpoint_id.c_str()); - // Generate the nonce to use for this connection. - std::int32_t nonce = prng_.NextInt32(); - - // The first message we have to send, after connecting, is to tell the - // endpoint about ourselves. - Exception write_exception = WriteConnectionRequestFrame( - channel.get(), client->GetLocalEndpointId(), info.endpoint_info, nonce, - GetConnectionMediumsByPriority()); - if (!write_exception.Ok()) { - NEARBY_LOG(INFO, "Failed to send connection request: id=%s", - endpoint_id.c_str()); - ProcessPreConnectionInitiationFailure( - endpoint_id, channel.get(), {Status::kEndpointIoError}, &result); - return; - } - - NEARBY_LOG(INFO, "adding connection to pending set: id=%s", - endpoint_id.c_str()); - - // We've successfully connected to the device, and are now about to jump on - // to the EncryptionRunner thread to start running our encryption protocol. - // We'll mark ourselves as pending in case we get another call to - // RequestConnection or OnIncomingConnection, so that we can cancel the - // connection if needed. - EndpointChannel* endpoint_channel = - pending_connections_ - .emplace(endpoint_id, - PendingConnectionInfo{ - .client = client, - .remote_endpoint_info = endpoint->endpoint_info, - .nonce = nonce, - .is_incoming = false, - .start_time = start_time, - .listener = info.listener, - .options = options, - .result = MakeSwapper(&result), - .channel = std::move(channel), - }) - .first->second.channel.get(); - - NEARBY_LOG(INFO, "Initiating secure connection: id=%s", - endpoint_id.c_str()); - // Next, we'll set up encryption. When it's done, our future will return and - // RequestConnection() will finish. - encryption_runner_.StartClient(client, endpoint_id, endpoint_channel, - GetResultListener()); - }); - NEARBY_LOG(INFO, "Waiting for connection to complete: id=%s", - endpoint_id.c_str()); - auto status = - WaitForResult(absl::StrCat("RequestConnection(", endpoint_id, ")"), - client->GetClientId(), &result); - NEARBY_LOG(INFO, "Wait is complete: id=%s; status=%d", endpoint_id.c_str(), - status.value); - return status; -} - -// Get any single discovered endpoint for a given endpoint_id. -BasePcpHandler::DiscoveredEndpoint* BasePcpHandler::GetDiscoveredEndpoint( - const std::string& endpoint_id) { - auto it = discovered_endpoints_.find(endpoint_id); - if (it == discovered_endpoints_.end()) { - return nullptr; - } - return it->second.get(); -} - -std::vector -BasePcpHandler::GetDiscoveredEndpoints(const std::string& endpoint_id) { - std::vector result; - auto it = discovered_endpoints_.equal_range(endpoint_id); - for (auto item = it.first; item != it.second; item++) { - result.push_back(item->second.get()); - } - std::sort(result.begin(), result.end(), - [this](DiscoveredEndpoint* a, DiscoveredEndpoint* b) -> bool { - return IsPreferred(*a, *b); - }); - return result; -} - -void BasePcpHandler::PendingConnectionInfo::SetCryptoContext( - std::unique_ptr ukey2) { - this->ukey2 = std::move(ukey2); -} - -bool BasePcpHandler::HasOutgoingConnections(ClientProxy* client) const { - for (const auto& item : pending_connections_) { - auto& connection = item.second; - if (!connection.is_incoming) { - return true; - } - } - return client->GetNumOutgoingConnections() > 0; -} - -bool BasePcpHandler::HasIncomingConnections(ClientProxy* client) const { - for (const auto& item : pending_connections_) { - auto& connection = item.second; - if (connection.is_incoming) { - return true; - } - } - return client->GetNumIncomingConnections() > 0; -} - -bool BasePcpHandler::CanSendOutgoingConnection(ClientProxy* client) const { - return true; -} - -bool BasePcpHandler::CanReceiveIncomingConnection(ClientProxy* client) const { - return true; -} - -Exception BasePcpHandler::WriteConnectionRequestFrame( - EndpointChannel* endpoint_channel, const std::string& local_endpoint_id, - const ByteArray& local_endpoint_info, std::int32_t nonce, - const std::vector& supported_mediums) { - return endpoint_channel->Write(parser::ForConnectionRequest( - local_endpoint_id, local_endpoint_info, nonce, supported_mediums)); -} - -void BasePcpHandler::ProcessPreConnectionInitiationFailure( - const std::string& endpoint_id, EndpointChannel* channel, Status status, - Future* result) { - if (channel != nullptr) { - channel->Close(); - } - - pending_connections_.erase(endpoint_id); - - if (result != nullptr) { - NEARBY_LOG(INFO, "Connection failed; aborting future"); - result->Set(status); - } -} - -void BasePcpHandler::ProcessPreConnectionResultFailure( - ClientProxy* client, const std::string& endpoint_id) { - auto item = pending_connections_.extract(endpoint_id); - endpoint_manager_->DiscardEndpoint(client, endpoint_id); - client->OnConnectionRejected(endpoint_id, {Status::kError}); -} - -bool BasePcpHandler::ShouldEnforceTopologyConstraints() const { - // Topology constraints only matter for the advertiser. - // For discoverers, we'll always enforce them. - if (advertising_options_.strategy.IsNone()) { - return true; - } - - return advertising_options_.enforce_topology_constraints; -} - -bool BasePcpHandler::AutoUpgradeBandwidth() const { - if (advertising_options_.strategy.IsNone()) { - return true; - } - - return advertising_options_.auto_upgrade_bandwidth; -} - -Status BasePcpHandler::AcceptConnection( - ClientProxy* client, const std::string& endpoint_id, - const PayloadListener& payload_listener) { - Future response; - RunOnPcpHandlerThread( - [this, client, endpoint_id, payload_listener, &response]() { - NEARBY_LOG(INFO, "AcceptConnection: id=%s", endpoint_id.c_str()); - if (!pending_connections_.count(endpoint_id)) { - NEARBY_LOG(INFO, "AcceptConnection: no pending connection for id=%s", - endpoint_id.c_str()); - response.Set({Status::kEndpointUnknown}); - return; - } - auto& connection_info = pending_connections_[endpoint_id]; - - // By this point in the flow, connection_info.channel has been - // nulled out because ownership of that EndpointChannel was passed on to - // EndpointChannelManager via a call to - // EndpointManager::registerEndpoint(), so we now need to get access to - // the EndpointChannel from the authoritative owner. - std::shared_ptr channel = - channel_manager_->GetChannelForEndpoint(endpoint_id); - if (channel == nullptr) { - NEARBY_LOG( - ERROR, - "Channel destroyed before Accept; bring down connection: id=%s", - endpoint_id.c_str()); - ProcessPreConnectionResultFailure(client, endpoint_id); - response.Set({Status::kEndpointUnknown}); - return; - } - - Exception write_exception = - channel->Write(parser::ForConnectionResponse(Status::kSuccess)); - if (!write_exception.Ok()) { - NEARBY_LOG(INFO, "AcceptConnection: failed to send response: id=%s", - endpoint_id.c_str()); - ProcessPreConnectionResultFailure(client, endpoint_id); - response.Set({Status::kEndpointIoError}); - return; - } - - NEARBY_LOG(INFO, "AcceptConnection: accepting locally: id=%s", - endpoint_id.c_str()); - connection_info.LocalEndpointAcceptedConnection(endpoint_id, - payload_listener); - EvaluateConnectionResult(client, endpoint_id, - false /* can_close_immediately */); - response.Set({Status::kSuccess}); - }); - - return WaitForResult(absl::StrCat("AcceptConnection(", endpoint_id, ")"), - client->GetClientId(), &response); -} - -Status BasePcpHandler::RejectConnection(ClientProxy* client, - const std::string& endpoint_id) { - Future response; - RunOnPcpHandlerThread([this, client, endpoint_id, &response]() { - NEARBY_LOG(INFO, "RejectConnection: id=%s", endpoint_id.c_str()); - if (!pending_connections_.count(endpoint_id)) { - NEARBY_LOG(INFO, "RejectConnection: no pending connection for id=%s", - endpoint_id.c_str()); - response.Set({Status::kEndpointUnknown}); - return; - } - auto& connection_info = pending_connections_[endpoint_id]; - - // By this point in the flow, connection_info->endpoint_channel_ has been - // nulled out because ownership of that EndpointChannel was passed on to - // EndpointChannelManager via a call to - // EndpointManager::registerEndpoint(), so we now need to get access to the - // EndpointChannel from the authoritative owner. - std::shared_ptr channel = - channel_manager_->GetChannelForEndpoint(endpoint_id); - if (channel == nullptr) { - NEARBY_LOG( - ERROR, - "Channel destroyed before Reject; bring down connection: id=%s", - endpoint_id.c_str()); - ProcessPreConnectionResultFailure(client, endpoint_id); - response.Set({Status::kEndpointUnknown}); - return; - } - - Exception write_exception = channel->Write( - parser::ForConnectionResponse(Status::kConnectionRejected)); - if (!write_exception.Ok()) { - NEARBY_LOG(INFO, "RejectConnection: failed to send response: id=%s", - endpoint_id.c_str()); - ProcessPreConnectionResultFailure(client, endpoint_id); - response.Set({Status::kEndpointIoError}); - return; - } - - NEARBY_LOG(INFO, "RejectConnection: rejecting locally: id=%s", - endpoint_id.c_str()); - connection_info.LocalEndpointRejectedConnection(endpoint_id); - EvaluateConnectionResult(client, endpoint_id, - false /* can_close_immediately */); - response.Set({Status::kSuccess}); - }); - - return WaitForResult(absl::StrCat("RejectConnection(", endpoint_id, ")"), - client->GetClientId(), &response); -} - -void BasePcpHandler::OnIncomingFrame(OfflineFrame& frame, - const std::string& endpoint_id, - ClientProxy* client, - proto::connections::Medium medium) { - CountDownLatch latch(1); - RunOnPcpHandlerThread([this, client, endpoint_id, frame, &latch]() { - NEARBY_LOG(INFO, "OnConnectionResponse: id=%s", endpoint_id.c_str()); - - if (client->HasRemoteEndpointResponded(endpoint_id)) { - NEARBY_LOG(INFO, "OnConnectionResponse: already handled; id=%s", - endpoint_id.c_str()); - return; - } - - const ConnectionResponseFrame& connection_response = - frame.v1().connection_response(); - - // For backward compatible, here still check both status and - // response parameters until the response feature is roll out in all - // supported devices. - bool accepted = false; - if (connection_response.has_response()) { - accepted = - connection_response.response() == ConnectionResponseFrame::ACCEPT; - } else { - accepted = connection_response.status() == Status::kSuccess; - } - if (accepted) { - NEARBY_LOG(INFO, "OnConnectionResponse: remote accepted; id=%s", - endpoint_id.c_str()); - client->RemoteEndpointAcceptedConnection(endpoint_id); - } else { - NEARBY_LOG(INFO, - "OnConnectionResponse: remote rejected; id=%s; status=%d", - endpoint_id.c_str(), connection_response.status()); - client->RemoteEndpointRejectedConnection(endpoint_id); - } - - EvaluateConnectionResult(client, endpoint_id, - /* can_close_immediately= */ true); - - latch.CountDown(); - }); - WaitForLatch("OnIncomingFrame()", &latch); -} - -void BasePcpHandler::OnEndpointDisconnect(ClientProxy* client, - const std::string& endpoint_id, - CountDownLatch* barrier) { - if (stop_.Get()) { - if (barrier) barrier->CountDown(); - return; - } - RunOnPcpHandlerThread([this, client, endpoint_id, barrier]() { - auto item = pending_alarms_.find(endpoint_id); - if (item != pending_alarms_.end()) { - auto& alarm = item->second; - alarm.Cancel(); - pending_alarms_.erase(item); - } - ProcessPreConnectionResultFailure(client, endpoint_id); - barrier->CountDown(); - }); -} - -ConnectionOptions BasePcpHandler::GetConnectionOptions() const { - return advertising_options_; -} - -ConnectionOptions BasePcpHandler::GetDiscoveryOptions() const { - return discovery_options_; -} - -void BasePcpHandler::OnEndpointFound( - ClientProxy* client, std::shared_ptr endpoint) { - // Check if we've seen this endpoint ID before. - std::string& endpoint_id = endpoint->endpoint_id; - NEARBY_LOG(INFO, "OnEndpointFound: id='%s' [enter]", endpoint_id.c_str()); - - auto range = discovered_endpoints_.equal_range(endpoint->endpoint_id); - - DiscoveredEndpoint* owned_endpoint = nullptr; - for (auto& item = range.first; item != range.second; ++item) { - auto& discovered_endpoint = item->second; - if (discovered_endpoint->medium != endpoint->medium) continue; - // Check if there was a info change. If there was, report the previous - // endpoint as lost. - if (discovered_endpoint->endpoint_info != endpoint->endpoint_info) { - OnEndpointLost(client, *discovered_endpoint); - discovered_endpoint = endpoint; // Replace endpoint. - OnEndpointFound(client, std::move(endpoint)); - return; - } else { - owned_endpoint = endpoint.get(); - break; - } - } - - if (!owned_endpoint) { - owned_endpoint = - discovered_endpoints_.emplace(endpoint_id, std::move(endpoint)) - ->second.get(); - } - - // Range is empty: this is the first endpoint we discovered so far. - // Report this endpoint_id to client. - if (range.first == range.second) { - NEARBY_LOG(INFO, "Adding new endpoint: id=%s", endpoint_id.c_str()); - // And, as it's the first time, report it to the client. - client->OnEndpointFound( - owned_endpoint->service_id, owned_endpoint->endpoint_id, - owned_endpoint->endpoint_info, owned_endpoint->medium); - } else { - NEARBY_LOGS(INFO) << "Adding new medium for endpoint: id=" << endpoint_id - << "; medium=" << owned_endpoint->medium; - } -} - -void BasePcpHandler::OnEndpointLost( - ClientProxy* client, const BasePcpHandler::DiscoveredEndpoint& endpoint) { - // Look up the DiscoveredEndpoint we have in our cache. - const auto* discovered_endpoint = GetDiscoveredEndpoint(endpoint.endpoint_id); - if (discovered_endpoint == nullptr) { - NEARBY_LOG(INFO, "No previous endpoint (nothing to lose): id=%s", - endpoint.endpoint_id.c_str()); - return; - } - - // Validate that the cached endpoint has the same info as the one reported as - // onLost. If the info differs, then no-op. This likely means that the remote - // device changed their info. We reported onFound for the new info and are - // just now figuring out that we lost the old info. - if (discovered_endpoint->endpoint_info != endpoint.endpoint_info) { - NEARBY_LOG(INFO, "Previous endpoint name mismatch; passed=%s; expected=%s", - absl::BytesToHexString(endpoint.endpoint_info.data()).c_str(), - absl::BytesToHexString(discovered_endpoint->endpoint_info.data()) - .c_str()); - return; - } - - auto item = discovered_endpoints_.extract(endpoint.endpoint_id); - if (!discovered_endpoints_.count(endpoint.endpoint_id)) { - client->OnEndpointLost(endpoint.service_id, endpoint.endpoint_id); - } -} - -bool BasePcpHandler::IsPreferred( - const BasePcpHandler::DiscoveredEndpoint& new_endpoint, - const BasePcpHandler::DiscoveredEndpoint& old_endpoint) { - std::vector mediums = - GetConnectionMediumsByPriority(); - // As we iterate through the list of mediums, we see if we run into the new - // endpoint's medium or the old endpoint's medium first. - for (const auto& medium : mediums) { - if (medium == new_endpoint.medium) { - // The new endpoint's medium came first. It's preferred! - return true; - } - - if (medium == old_endpoint.medium) { - // The old endpoint's medium came first. Stick with the old endpoint! - return false; - } - } - std::string medium_string; - for (const auto& medium : mediums) { - absl::StrAppend(&medium_string, medium, "; "); - } - NEARBY_LOG(FATAL, - "Failed to determine preferred medium; bailing out; mediums=%s; " - "new=%d; old=%d", - medium_string.c_str(), new_endpoint.medium, old_endpoint.medium); - return false; -} - -Exception BasePcpHandler::OnIncomingConnection( - ClientProxy* client, const ByteArray& remote_endpoint_info, - std::unique_ptr channel, - proto::connections::Medium medium) { - absl::Time start_time = SystemClock::ElapsedRealtime(); - - // Fixes an NPE in ClientProxy.OnConnectionAccepted. The crash happened when - // the client stopped advertising and we nulled out state, followed by an - // incoming connection where we attempted to check that state. - if (!client->IsAdvertising()) { - NEARBY_LOG(WARNING, - "Ignoring incoming connection because client 0x%" PRIX64 - " is no longer advertising.", - client->GetClientId()); - return {Exception::kIo}; - } - - // Endpoints connecting to us will always tell us about themselves first. - ExceptionOr wrapped_frame = - ReadConnectionRequestFrame(channel.get()); - - if (!wrapped_frame.ok()) { - if (wrapped_frame.exception()) { - NEARBY_LOG( - ERROR, - "Failed to parse incoming connection request; client_id=0x%" PRIX64 - "; device=%s", - client->GetClientId(), - absl::BytesToHexString(remote_endpoint_info.data()).c_str()); - ProcessPreConnectionInitiationFailure("", channel.get(), {Status::kError}, - nullptr); - return {Exception::kSuccess}; - } - return wrapped_frame.GetException(); - } - - OfflineFrame& frame = wrapped_frame.result(); - const ConnectionRequestFrame& connection_request = - frame.v1().connection_request(); - NEARBY_LOG(INFO, - "Incoming connection request; client_id=0x%" PRIX64 - "; device=%s; id=%s", - client->GetClientId(), - absl::BytesToHexString(remote_endpoint_info.data()).c_str(), - connection_request.endpoint_id().c_str()); - if (client->IsConnectedToEndpoint(connection_request.endpoint_id())) { - return {Exception::kIo}; - } - - // If we've already sent out a connection request to this endpoint, then this - // is where we need to decide which connection to break. - if (BreakTie(client, connection_request.endpoint_id(), - connection_request.nonce(), channel.get())) { - return {Exception::kSuccess}; - } - - // If our child class says we can't accept any more incoming connections, - // listen to them. - if (ShouldEnforceTopologyConstraints() && - !CanReceiveIncomingConnection(client)) { - return {Exception::kIo}; - } - - // The ConnectionRequest frame has two fields that both contain the - // EndpointInfo. The legacy field stores it as a string while the newer field - // stores it as a byte array. We'll attempt to grab from the newer field, but - // will accept the older string if it's all that exists. - const ByteArray endpoint_info{connection_request.has_endpoint_info() - ? connection_request.endpoint_info() - : connection_request.endpoint_name()}; - - // We've successfully connected to the device, and are now about to jump on to - // the EncryptionRunner thread to start running our encryption protocol. We'll - // mark ourselves as pending in case we get another call to RequestConnection - // or OnIncomingConnection, so that we can cancel the connection if needed. - auto* owned_channel = - pending_connections_ - .emplace(connection_request.endpoint_id(), - PendingConnectionInfo{ - .client = client, - .remote_endpoint_info = endpoint_info, - .nonce = connection_request.nonce(), - .is_incoming = true, - .start_time = start_time, - .listener = advertising_listener_, - .supported_mediums = - parser::ConnectionRequestMediumsToMediums( - connection_request), - .channel = std::move(channel), - }) - .first->second.channel.get(); - - // Next, we'll set up encryption. - encryption_runner_.StartServer(client, connection_request.endpoint_id(), - owned_channel, GetResultListener()); - return {Exception::kSuccess}; -} - -bool BasePcpHandler::BreakTie(ClientProxy* client, - const std::string& endpoint_id, - std::int32_t incoming_nonce, - EndpointChannel* endpoint_channel) { - auto it = pending_connections_.find(endpoint_id); - if (it != pending_connections_.end()) { - BasePcpHandler::PendingConnectionInfo& info = it->second; - - NEARBY_LOG(INFO, "BreakTie: id=%s", endpoint_id.c_str()); - // Break the lowest connection. In the (extremely) rare case of a tie, break - // both. - if (info.nonce > incoming_nonce) { - // Our connection won! Clean up their connection. - endpoint_channel->Close(); - - NEARBY_LOG(INFO, "BreakTie: We won; id=%s", endpoint_id.c_str()); - return true; - } else if (info.nonce < incoming_nonce) { - // Aw, we lost. Clean up our connection, and then we'll let their - // connection continue on. - ProcessTieBreakLoss(client, endpoint_id, &info); - - NEARBY_LOG(INFO, "BreakTie: We lost; id=%s", endpoint_id.c_str()); - } else { - // Oh. Huh. We both lost. Well, that's awkward. We'll clean up both and - // just force the devices to retry. - endpoint_channel->Close(); - - ProcessTieBreakLoss(client, endpoint_id, &info); - - NEARBY_LOG(INFO, "BreakTie: Both lost; id=%s", endpoint_id.c_str()); - return true; - } - } - - return false; -} - -void BasePcpHandler::ProcessTieBreakLoss( - ClientProxy* client, const std::string& endpoint_id, - BasePcpHandler::PendingConnectionInfo* info) { - ProcessPreConnectionInitiationFailure(endpoint_id, info->channel.get(), - {Status::kEndpointIoError}, - info->result.get()); - info->result = nullptr; - ProcessPreConnectionResultFailure(client, endpoint_id); -} - -void BasePcpHandler::InitiateBandwidthUpgrade( - ClientProxy* client, const std::string& endpoint_id, - const std::vector& supported_mediums) { - // When we successfully connect to a remote endpoint and a bandwidth upgrade - // medium has not yet been decided, we'll pick the highest bandwidth medium - // supported by both us and the remote endpoint. Once we pick a medium, all - // future connections will use it too. eg. If we chose Wifi LAN, we'll attempt - // to upgrade the 2nd, 3rd, etc remote endpoints with Wifi LAN even if they're - // on a different network (or had a better medium). This is a quick and easy - // way to prevent mediums, like Wifi Hotspot, from interfering with active - // connections (although it's suboptimal for bandwidth throughput). When all - // endpoints disconnect, we reset the bandwidth upgrade medium. - Medium bwu_medium = bwu_medium_.Get(); - if (bwu_medium == Medium::UNKNOWN_MEDIUM) { - bwu_medium = ChooseBestUpgradeMedium(supported_mediums); - bwu_medium_.Set(bwu_medium); - } - - if (AutoUpgradeBandwidth() && bwu_medium != Medium::UNKNOWN_MEDIUM) { - bwu_manager_->InitiateBwuForEndpoint(client, endpoint_id, bwu_medium); - } -} - -proto::connections::Medium BasePcpHandler::ChooseBestUpgradeMedium( - const std::vector& their_supported_mediums) { - // If the remote side did not report their supported mediums, choose an - // appropriate default. - std::vector their_mediums = - their_supported_mediums; - if (their_supported_mediums.empty()) { - their_mediums.push_back(GetDefaultUpgradeMedium()); - } - - // Otherwise, pick the best medium we support. - std::vector my_mediums = - GetConnectionMediumsByPriority(); - for (const auto& my_medium : my_mediums) { - for (const auto& their_medium : their_mediums) { - if (my_medium == their_medium) { - return my_medium; - } - } - } - - return proto::connections::Medium::UNKNOWN_MEDIUM; -} - -bool BasePcpHandler::AppendRemoteBluetoothMacAddressEndpoint( - const std::string& endpoint_id, - const std::string& remote_bluetooth_mac_address) { - if (!discovery_options_.allowed.bluetooth) { - return false; - } - - auto it = discovered_endpoints_.equal_range(endpoint_id); - if (it.first == it.second) { - return false; - } - auto endpoint = it.first->second.get(); - for (auto item = it.first; item != it.second; item++) { - if (item->second->medium == proto::connections::Medium::BLUETOOTH) { - NEARBY_LOGS(INFO) - << "Cannot append remote Bluetooth MAC Address endpoint, because the " - "endpoint has already been found over Bluetooth " - << "[" << remote_bluetooth_mac_address << "]"; - return false; - } - } - - auto remote_bluetooth_device = - mediums_->GetBluetoothClassic().GetRemoteDevice( - remote_bluetooth_mac_address); - if (!remote_bluetooth_device.IsValid()) { - NEARBY_LOGS(INFO) << "Cannot append remote Bluetooth MAC Address endpoint, " - "because a valid " - "Bluetooth device could not be derived " - << "[" << remote_bluetooth_mac_address << "]"; - return false; - } - - auto bluetooth_endpoint = - std::make_shared(BluetoothEndpoint{ - { - endpoint_id, - endpoint->endpoint_info, - endpoint->service_id, - proto::connections::Medium::BLUETOOTH, - WebRtcState::kUnconnectable - }, - remote_bluetooth_device, - }); - - discovered_endpoints_.emplace(endpoint_id, std::move(bluetooth_endpoint)); - return true; -} - -bool BasePcpHandler::AppendWebRTCEndpoint(const std::string& endpoint_id) { - if (!discovery_options_.allowed.web_rtc) { - return false; - } - - bool should_connect_web_rtc = false; - auto it = discovered_endpoints_.equal_range(endpoint_id); - if (it.first == it.second) return false; - auto endpoint = it.first->second.get(); - for (auto item = it.first; item != it.second; item++) { - if (item->second->web_rtc_state != WebRtcState::kUnconnectable) { - should_connect_web_rtc = true; - break; - } - } - if (!should_connect_web_rtc) return false; - - auto webrtc_endpoint = - std::make_shared(WebRtcEndpoint{ - { - endpoint_id, - endpoint->endpoint_info, - endpoint->service_id, - proto::connections::Medium::WEB_RTC, - WebRtcState::kConnectable - }, - CreatePeerIdFromAdvertisement( - endpoint->service_id, - endpoint->endpoint_id, - endpoint->endpoint_info), - }); - - discovered_endpoints_.emplace(endpoint_id, std::move(webrtc_endpoint)); - return true; -} - -void BasePcpHandler::EvaluateConnectionResult(ClientProxy* client, - const std::string& endpoint_id, - bool can_close_immediately) { - // Short-circuit immediately if we're not in an actionable state yet. We will - // be called again once the other side has made their decision. - if (!client->IsConnectionAccepted(endpoint_id) && - !client->IsConnectionRejected(endpoint_id)) { - if (!client->HasLocalEndpointResponded(endpoint_id)) { - NEARBY_LOG(INFO, "ConnectionResult: local client did not respond; id=%s", - endpoint_id.c_str()); - } else if (!client->HasRemoteEndpointResponded(endpoint_id)) { - NEARBY_LOG(INFO, "ConnectionResult: remote client did not respond; id=%s", - endpoint_id.c_str()); - } - return; - } - - // Clean up the endpoint channel from our list of 'pending' connections. It's - // no longer pending. - auto it = pending_connections_.find(endpoint_id); - if (it == pending_connections_.end()) { - NEARBY_LOG(INFO, "No pending connection to evaluate; id=%s", - endpoint_id.c_str()); - return; - } - - auto pair = pending_connections_.extract(it); - BasePcpHandler::PendingConnectionInfo& connection_info = pair.mapped(); - bool is_connection_accepted = client->IsConnectionAccepted(endpoint_id); - - Status response_code; - if (is_connection_accepted) { - NEARBY_LOG(INFO, "Pending connection accepted; id=%s", endpoint_id.c_str()); - response_code = {Status::kSuccess}; - - // Both sides have accepted, so we can now start talking over encrypted - // channels - // Now, after both parties accepted connection (presumably after verifying & - // matching security tokens), we are allowed to extract the shared key. - auto ukey2 = std::move(connection_info.ukey2); - bool succeeded = ukey2->VerifyHandshake(); - CHECK(succeeded); // If this fails, it's a UKEY2 protocol bug. - auto context = ukey2->ToConnectionContext(); - CHECK(context); // there is no way how this can fail, if Verify succeeded. - // If it did, it's a UKEY2 protocol bug. - - channel_manager_->EncryptChannelForEndpoint(endpoint_id, - std::move(context)); - } else { - NEARBY_LOG(INFO, "Pending connection rejected; id=%s", endpoint_id.c_str()); - response_code = {Status::kConnectionRejected}; - } - - // Invoke the client callback to let it know of the connection result. - if (response_code.Ok()) { - client->OnConnectionAccepted(endpoint_id); - } else { - client->OnConnectionRejected(endpoint_id, response_code); - } - - // If the connection failed, clean everything up and short circuit. - if (!is_connection_accepted) { - // Clean up the channel in EndpointManager if it's no longer required. - if (can_close_immediately) { - endpoint_manager_->DiscardEndpoint(client, endpoint_id); - } else { - pending_alarms_.emplace( - endpoint_id, - CancelableAlarm( - "BasePcpHandler.evaluateConnectionResult() delayed close", - [this, client, endpoint_id]() { - endpoint_manager_->DiscardEndpoint(client, endpoint_id); - }, - kRejectedConnectionCloseDelay, &alarm_executor_)); - } - - return; - } - - // Kick off the bandwidth upgrade for incoming connections. - if (connection_info.is_incoming) { - InitiateBandwidthUpgrade(client, endpoint_id, - connection_info.supported_mediums); - } -} - -ExceptionOr BasePcpHandler::ReadConnectionRequestFrame( - EndpointChannel* endpoint_channel) { - if (endpoint_channel == nullptr) { - return ExceptionOr(Exception::kIo); - } - - // To avoid a device connecting but never sending their introductory frame, we - // time out the connection after a certain amount of time. - CancelableAlarm timeout_alarm( - absl::StrCat("PcpHandler(", this->GetStrategy().GetName(), - ")::ReadConnectionRequestFrame"), - [endpoint_channel]() { endpoint_channel->Close(); }, - kConnectionRequestReadTimeout, &alarm_executor_); - // Do a blocking read to try and find the ConnectionRequestFrame - ExceptionOr wrapped_bytes = endpoint_channel->Read(); - timeout_alarm.Cancel(); - - if (!wrapped_bytes.ok()) { - return ExceptionOr(wrapped_bytes.exception()); - } - - ByteArray bytes = std::move(wrapped_bytes.result()); - ExceptionOr wrapped_frame = parser::FromBytes(bytes); - if (wrapped_frame.GetException().Raised(Exception::kInvalidProtocolBuffer)) { - return ExceptionOr(Exception::kIo); - } - - OfflineFrame& frame = wrapped_frame.result(); - if (V1Frame::CONNECTION_REQUEST != parser::GetFrameType(frame)) { - return ExceptionOr(Exception::kIo); - } - - return wrapped_frame; -} - -///////////////////// BasePcpHandler::PendingConnectionInfo /////////////////// - -BasePcpHandler::PendingConnectionInfo::~PendingConnectionInfo() { - if (result != nullptr) { - NEARBY_LOG(INFO, "Future was not set; destroying info"); - result->Set({Status::kError}); - } - - if (channel != nullptr) { - channel->Close(proto::connections::DisconnectionReason::SHUTDOWN); - } - - // Destroy crypto context now; for some reason, crypto context destructor - // segfaults if it is not destroyed here. - this->ukey2.reset(); -} - -void BasePcpHandler::PendingConnectionInfo::LocalEndpointAcceptedConnection( - const std::string& endpoint_id, const PayloadListener& payload_listener) { - client->LocalEndpointAcceptedConnection(endpoint_id, payload_listener); -} - -void BasePcpHandler::PendingConnectionInfo::LocalEndpointRejectedConnection( - const std::string& endpoint_id) { - client->LocalEndpointRejectedConnection(endpoint_id); -} - -mediums::PeerId BasePcpHandler::CreatePeerIdFromAdvertisement( - const std::string& service_id, const std::string& endpoint_id, - const ByteArray& endpoint_info) { - std::string seed = - absl::StrCat(service_id, endpoint_id, std::string(endpoint_info)); - return mediums::PeerId::FromSeed(ByteArray(std::move(seed))); -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/base_pcp_handler.h b/cpp/core_v2/internal/base_pcp_handler.h deleted file mode 100644 index 9ed68a08..00000000 --- a/cpp/core_v2/internal/base_pcp_handler.h +++ /dev/null @@ -1,500 +0,0 @@ -#ifndef CORE_V2_INTERNAL_BASE_PCP_HANDLER_H_ -#define CORE_V2_INTERNAL_BASE_PCP_HANDLER_H_ - -#include -#include -#include -#include - -#include "core_v2/internal/bwu_manager.h" -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/encryption_runner.h" -#include "core_v2/internal/endpoint_channel_manager.h" -#include "core_v2/internal/endpoint_manager.h" -#include "core_v2/internal/mediums/mediums.h" -#include "core_v2/internal/mediums/webrtc.h" -#include "core_v2/internal/pcp.h" -#include "core_v2/internal/pcp_handler.h" -#include "core_v2/listeners.h" -#include "core_v2/options.h" -#include "core_v2/status.h" -#include "proto/connections/offline_wire_formats.pb.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/prng.h" -#include "platform_v2/public/atomic_boolean.h" -#include "platform_v2/public/atomic_reference.h" -#include "platform_v2/public/cancelable_alarm.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/future.h" -#include "platform_v2/public/scheduled_executor.h" -#include "platform_v2/public/single_thread_executor.h" -#include "platform_v2/public/system_clock.h" -#include "proto/connections_enums.pb.h" -#include "securegcm/d2d_connection_context_v1.h" -#include "securegcm/ukey2_handshake.h" -#include "absl/container/btree_map.h" -#include "absl/container/flat_hash_map.h" -#include "absl/time/time.h" - -namespace location { -namespace nearby { -namespace connections { - -// Define a class that supports move operation for pointers using std::swap. -// It replicates std::unique_ptr<> behavior, but it does not own the pointer, -// so it does not attempt destroy it. -// This approach was recommended during code review, as a better alternative to -// reuse of std::unique_ptr<> with custom no-op deleter, for the sake of -// readability. -template -class Swapper { - public: - Swapper(T* pointer) : pointer_(pointer) {} // NOLINT. - Swapper(Swapper&& other) { *this = std::move(other); } - Swapper& operator=(Swapper&& other) { - std::swap(pointer_, other.pointer_); - return *this; - } - T* operator->() const { return pointer_; } - T& operator*() { return *pointer_; } - operator T*() { return pointer_; } // NOLINT. - T* get() const { return pointer_; } - void reset() { pointer_ = nullptr; } - - private: - T* pointer_ = nullptr; -}; - -template -Swapper MakeSwapper(T* value) { - return Swapper(value); -} - -// Represents the WebRtc state that mediums are connectable or not. -enum class WebRtcState { - kUndefined = 0, - kConnectable = 1, - kUnconnectable = 2, -}; - -// A base implementation of the PcpHandler interface that takes care of all -// bookkeeping and handshake protocols that are common across all PcpHandler -// implementations -- thus, every concrete PcpHandler implementation must extend -// this class, so that they can focus exclusively on the medium-specific -// operations. -class BasePcpHandler : public PcpHandler, - public EndpointManager::FrameProcessor { - public: - using FrameProcessor = EndpointManager::FrameProcessor; - - // TODO(apolyudov): Add SecureRandom. - BasePcpHandler(Mediums* mediums, EndpointManager* endpoint_manager, - EndpointChannelManager* channel_manager, - BwuManager* bwu_manager, Pcp pcp); - ~BasePcpHandler() override; - BasePcpHandler(BasePcpHandler&&) = delete; - BasePcpHandler& operator=(BasePcpHandler&&) = delete; - - // Starts advertising. Once successfully started, changes ClientProxy's state. - // Notifies ConnectionListener (info.listener) in case of any event. - // See - // https://source.corp.google.com/piper///depot/google3/core_v2/listeners.h;l=78 - Status StartAdvertising(ClientProxy* client, const std::string& service_id, - const ConnectionOptions& options, - const ConnectionRequestInfo& info) override; - - // Stops Advertising is active, and changes CLientProxy state, - // otherwise does nothing. - void StopAdvertising(ClientProxy* client) override; - - // Starts discovery of endpoints that may be advertising. - // Updates ClientProxy state once discovery started. - // DiscoveryListener will get called in case of any event. - Status StartDiscovery(ClientProxy* client, const std::string& service_id, - const ConnectionOptions& options, - const DiscoveryListener& listener) override; - - // Stops Discovery if it is active, and changes CLientProxy state, - // otherwise does nothing. - void StopDiscovery(ClientProxy* client) override; - - // Requests a newly discovered remote endpoint it to form a connection. - // Updates state on ClientProxy. - Status RequestConnection(ClientProxy* client, const std::string& endpoint_id, - const ConnectionRequestInfo& info, - const ConnectionOptions& options) override; - - // Called by either party to accept connection on their part. - // Until both parties call it, connection will not reach a data phase. - // Updates state in ClientProxy. - Status AcceptConnection(ClientProxy* client, const std::string& endpoint_id, - const PayloadListener& payload_listener) override; - - // Called by either party to reject connection on their part. - // If either party does call it, connection will terminate. - // Updates state in ClientProxy. - Status RejectConnection(ClientProxy* client, - const std::string& endpoint_id) override; - - // @EndpointManagerReaderThread - void OnIncomingFrame(OfflineFrame& frame, const std::string& endpoint_id, - ClientProxy* client, - proto::connections::Medium medium) override; - - // Called when an endpoint disconnects while we're waiting for both sides to - // approve/reject the connection. - // @EndpointManagerThread - void OnEndpointDisconnect(ClientProxy* client, const std::string& endpoint_id, - CountDownLatch* barrier) override; - - Pcp GetPcp() const override { return pcp_; } - Strategy GetStrategy() const override { return strategy_; } - Medium GetBwuMedium() const { return bwu_medium_.Get(); } - void DisconnectFromEndpointManager(); - - protected: - // The result of a call to startAdvertisingImpl() or startDiscoveryImpl(). - struct StartOperationResult { - Status status; - // If success, the mediums on which we are now advertising/discovering, for - // analytics. - std::vector mediums; - }; - - // Represents an endpoint that we've discovered. Typically, the implementation - // will know how to connect to this endpoint if asked. (eg. It holds on to a - // BluetoothDevice) - // - // NOTE(DiscoveredEndpoint): - // Specific protocol is expected to derive from it, as follows: - // struct ProtocolEndpoint : public DiscoveredEndpoint { - // ProtocolContext context; - // }; - // Protocol then allocates instance with std::make_shared(), - // and passes this instance to OnEndpointFound() method. - // When calling OnEndpointLost(), protocol does not need to pass the same - // instance (but it can if implementation desires to do so). - // BasePcpHandler will hold on to the shared_ptr. - struct DiscoveredEndpoint { - DiscoveredEndpoint(std::string endpoint_id, ByteArray endpoint_info, - std::string service_id, - proto::connections::Medium medium, - WebRtcState web_rtc_state) - : endpoint_id(std::move(endpoint_id)), - endpoint_info(std::move(endpoint_info)), - service_id(std::move(service_id)), - medium(medium), - web_rtc_state(web_rtc_state) {} - virtual ~DiscoveredEndpoint() = default; - - std::string endpoint_id; - ByteArray endpoint_info; - std::string service_id; - proto::connections::Medium medium; - WebRtcState web_rtc_state; - }; - - struct BluetoothEndpoint : public DiscoveredEndpoint { - BluetoothEndpoint(DiscoveredEndpoint endpoint, BluetoothDevice device) - : DiscoveredEndpoint(std::move(endpoint)), - bluetooth_device(std::move(device)) {} - - BluetoothDevice bluetooth_device; - }; - - struct WifiLanEndpoint : public DiscoveredEndpoint { - WifiLanEndpoint(DiscoveredEndpoint endpoint, WifiLanService service) - : DiscoveredEndpoint(std::move(endpoint)), - wifi_lan_service(std::move(service)) {} - - WifiLanService wifi_lan_service; - }; - - struct WebRtcEndpoint : public DiscoveredEndpoint { - WebRtcEndpoint(DiscoveredEndpoint endpoint, mediums::PeerId peer_id) - : DiscoveredEndpoint(std::move(endpoint)), - peer_id(std::move(peer_id)) {} - - mediums::PeerId peer_id; - }; - - struct ConnectImplResult { - proto::connections::Medium medium = - proto::connections::Medium::UNKNOWN_MEDIUM; - Status status = {Status::kError}; - std::unique_ptr endpoint_channel; - }; - - void RunOnPcpHandlerThread(Runnable runnable); - - ConnectionOptions GetConnectionOptions() const; - ConnectionOptions GetDiscoveryOptions() const; - - // @PcpHandlerThread - void OnEndpointFound(ClientProxy* client, - std::shared_ptr endpoint); - - // @PcpHandlerThread - void OnEndpointLost(ClientProxy* client, const DiscoveredEndpoint& endpoint); - - Exception OnIncomingConnection( - ClientProxy* client, const ByteArray& remote_endpoint_info, - std::unique_ptr endpoint_channel, - proto::connections::Medium medium); // throws Exception::IO - - virtual bool HasOutgoingConnections(ClientProxy* client) const; - virtual bool HasIncomingConnections(ClientProxy* client) const; - - virtual bool CanSendOutgoingConnection(ClientProxy* client) const; - virtual bool CanReceiveIncomingConnection(ClientProxy* client) const; - - // @PcpHandlerThread - virtual StartOperationResult StartAdvertisingImpl( - ClientProxy* client, const std::string& service_id, - const std::string& local_endpoint_id, - const ByteArray& local_endpoint_info, - const ConnectionOptions& options) = 0; - // @PcpHandlerThread - virtual Status StopAdvertisingImpl(ClientProxy* client) = 0; - - // @PcpHandlerThread - virtual StartOperationResult StartDiscoveryImpl( - ClientProxy* client, const std::string& service_id, - const ConnectionOptions& options) = 0; - // @PcpHandlerThread - virtual Status StopDiscoveryImpl(ClientProxy* client) = 0; - - // @PcpHandlerThread - virtual ConnectImplResult ConnectImpl(ClientProxy* client, - DiscoveredEndpoint* endpoint) = 0; - - virtual std::vector - GetConnectionMediumsByPriority() = 0; - virtual proto::connections::Medium GetDefaultUpgradeMedium() = 0; - - // Returns the first discovered endpoint for the given endpoint_id. - DiscoveredEndpoint* GetDiscoveredEndpoint(const std::string& endpoint_id); - - // Returns a vector of discovered endpoints, sorted in order of decreasing - // preference. - std::vector GetDiscoveredEndpoints( - const std::string& endpoint_id); - - mediums::PeerId CreatePeerIdFromAdvertisement(const string& service_id, - const string& endpoint_id, - const ByteArray& endpoint_info); - - Mediums* mediums_; - EndpointManager* endpoint_manager_; - EndpointChannelManager* channel_manager_; - - private: - struct PendingConnectionInfo { - PendingConnectionInfo() = default; - PendingConnectionInfo(PendingConnectionInfo&& other) = default; - PendingConnectionInfo& operator=(PendingConnectionInfo&&) = default; - ~PendingConnectionInfo(); - - // Passes crypto context that we acquired in DH session for temporary - // ownership here. - void SetCryptoContext(std::unique_ptr ukey2); - - // Pass Accept notification to client. - void LocalEndpointAcceptedConnection( - const std::string& endpoint_id, - const PayloadListener& payload_listener); - - // Pass Reject notification to client. - void LocalEndpointRejectedConnection(const std::string& endpoint_id); - - // Client state tracker to report events to. Never changes. Always valid. - ClientProxy* client = nullptr; - // Peer endpoint info, or empty, if not discovered yet. May change. - ByteArray remote_endpoint_info; - std::int32_t nonce = 0; - bool is_incoming = false; - absl::Time start_time{absl::InfinitePast()}; - // Client callbacks. Always valid. - ConnectionListener listener; - ConnectionOptions options; - - // Only set for outgoing connections. If set, we must call - // result->Set() when connection is established, or rejected. - Swapper> result = nullptr; - - // Only (possibly) vector for incoming connections. - std::vector supported_mediums; - - // Keep track of a channel before we pass it to EndpointChannelManager. - std::unique_ptr channel; - - // Crypto context; initially empty; established first thing after channel - // creation by running UKey2 session. While it is in progress, we keep track - // of channel ourselves. Once it is done, we pass channel over to - // EndpointChannelManager. We keep crypto context until connection is - // accepted. Crypto context is passed over to channel_manager_ before - // switching to connected state, where Payload may be exchanged. - std::unique_ptr ukey2; - }; - - // @EncryptionRunnerThread - // Called internally when DH session has negotiated a key successfully. - void OnEncryptionSuccessImpl(const std::string& endpoint_id, - std::unique_ptr ukey2, - const std::string& auth_token, - const ByteArray& raw_auth_token); - - // @EncryptionRunnerThread - // Called internally when DH session was not able to negotiate a key. - void OnEncryptionFailureImpl(const std::string& endpoint_id, - EndpointChannel* channel); - - EncryptionRunner::ResultListener GetResultListener(); - - void OnEncryptionSuccessRunnable( - const std::string& endpoint_id, - std::unique_ptr ukey2, - const std::string& auth_token, const ByteArray& raw_auth_token); - void OnEncryptionFailureRunnable(const std::string& endpoint_id, - EndpointChannel* endpoint_channel); - - static Exception WriteConnectionRequestFrame( - EndpointChannel* endpoint_channel, const std::string& local_endpoint_id, - const ByteArray& local_endpoint_info, std::int32_t nonce, - const std::vector& supported_mediums); - - static constexpr absl::Duration kConnectionRequestReadTimeout = - absl::Seconds(2); - static constexpr absl::Duration kRejectedConnectionCloseDelay = - absl::Seconds(2); - - void OnConnectionResponse(ClientProxy* client, const std::string& endpoint_id, - const OfflineFrame& frame); - - // Returns true if the new endpoint is preferred over the old endpoint. - bool IsPreferred(const BasePcpHandler::DiscoveredEndpoint& new_endpoint, - const BasePcpHandler::DiscoveredEndpoint& old_endpoint); - - // Returns true, if connection party should respect the specified topology. - bool ShouldEnforceTopologyConstraints() const; - - // Returns true, if connection party should attempt to upgrade itself to - // use a higher bandwidth medium, if it is available. - bool AutoUpgradeBandwidth() const; - - // Returns true if the incoming connection should be killed. This only - // happens when an incoming connection arrives while we have an outgoing - // connection to the same endpoint and we need to stop one connection. - bool BreakTie(ClientProxy* client, const std::string& endpoint_id, - std::int32_t incoming_nonce, EndpointChannel* channel); - // We're not sure how far our outgoing connection has gotten. We may (or may - // not) have called ClientProxy::OnConnectionInitiated. Therefore, we'll - // call both preInit and preResult failures. - void ProcessTieBreakLoss(ClientProxy* client, const std::string& endpoint_id, - PendingConnectionInfo* info); - - // Called when an incoming connection has been accepted by both sides. - // - // @param client_proxy The client - // @param endpoint_id The id of the remote device - // @param supported_mediums The mediums supported by the remote device. - // Empty - // for outgoing connections and older devices that don't report their - // supported mediums. - void InitiateBandwidthUpgrade( - ClientProxy* client, const std::string& endpoint_id, - const std::vector& supported_mediums); - - // Returns the optimal medium supported by both devices. - proto::connections::Medium ChooseBestUpgradeMedium( - const std::vector& supported_mediums); - - // Returns true if the bluetooth endpoint based on remote bluetooth mac - // address is created and appended into discovered_endpoints_ with key - // endpoint_id. - bool AppendRemoteBluetoothMacAddressEndpoint( - const std::string& endpoint_id, - const std::string& remote_bluetooth_mac_address); - - // Returns true if the webrtc endpoint is created and appended into - // discovered_endpoints_ with key endpoint_id. - bool AppendWebRTCEndpoint(const std::string& endpoint_id); - - void ProcessPreConnectionInitiationFailure(const std::string& endpoint_id, - EndpointChannel* channel, - Status status, - Future* result); - void ProcessPreConnectionResultFailure(ClientProxy* client, - const std::string& endpoint_id); - - // Called when either side accepts/rejects the connection, but only takes - // effect after both have accepted or one side has rejected. - // - // NOTE: We also take in a 'can_close_immediately' variable. This is because - // any writes in transit are dropped when we close. To avoid having a reject - // write being dropped (which causes the other side to report - // onResult(DISCONNECTED) instead of onResult(REJECTED)), we delay our - // close. If the other side behaves properly, we shouldn't even see the - // delay (because they will also close the connection). - void EvaluateConnectionResult(ClientProxy* client, - const std::string& endpoint_id, - bool can_close_immediately); - - ExceptionOr ReadConnectionRequestFrame( - EndpointChannel* channel); - - void WaitForLatch(const std::string& method_name, CountDownLatch* latch); - Status WaitForResult(const std::string& method_name, std::int64_t client_id, - Future* future); - - AtomicReference bwu_medium_{Medium::UNKNOWN_MEDIUM}; - ScheduledExecutor alarm_executor_; - SingleThreadExecutor serial_executor_; - - // A map of endpoint id -> PendingConnectionInfo. Entries in this map imply - // that there is an active connection to the endpoint and we're waiting for - // both sides to accept before allowing payloads through. Once the fate of - // the connection is decided (either accepted or rejected), it should be - // removed from this map. - absl::flat_hash_map pending_connections_; - // A map of endpoint id -> DiscoveredEndpoint. - absl::btree_multimap> - discovered_endpoints_; - // A map of endpoint id -> alarm. These alarms delay closing the - // EndpointChannel to give the other side enough time to read the rejection - // message. It's expected that the other side will close the connection - // after reading the message (in which case, this alarm should be cancelled - // as it's no longer needed), but this alarm is the fallback in case that - // doesn't happen. - absl::flat_hash_map pending_alarms_; - - // The active ClientProxy's advertising constraints. Empty() - // returns true if the client hasn't started advertising false otherwise. - // Note: this is not cleared when the client stops advertising because it - // might still be useful downstream of advertising (eg: establishing - // connections, performing bandwidth upgrades, etc.) - ConnectionOptions advertising_options_; - // The active ClientProxy's connection lifecycle listener. Non-null while - // advertising. - ConnectionListener advertising_listener_; - - // The active ClientProxy's discovery constraints. Null if the client - // hasn't started discovering. Note: this is not cleared when the client - // stops discovering because it might still be useful downstream of - // discovery (eg: connection speed, etc.) - ConnectionOptions discovery_options_; - - AtomicBoolean stop_{false}; - Pcp pcp_; - Strategy strategy_{PcpToStrategy(pcp_)}; - Prng prng_; - EncryptionRunner encryption_runner_; - BwuManager* bwu_manager_; - EndpointManager::FrameProcessor::Handle handle_ = nullptr; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_BASE_PCP_HANDLER_H_ diff --git a/cpp/core_v2/internal/ble_advertisement.cc b/cpp/core_v2/internal/ble_advertisement.cc deleted file mode 100644 index ed3bee6b..00000000 --- a/cpp/core_v2/internal/ble_advertisement.cc +++ /dev/null @@ -1,259 +0,0 @@ -#include "core_v2/internal/ble_advertisement.h" - -#include - -#include "core_v2/internal/base_pcp_handler.h" -#include "platform_v2/base/base_input_stream.h" -#include "platform_v2/public/logging.h" -#include "absl/strings/escaping.h" - -namespace location { -namespace nearby { -namespace connections { - -BleAdvertisement::BleAdvertisement(Version version, Pcp pcp, - const ByteArray& service_id_hash, - const std::string& endpoint_id, - const ByteArray& endpoint_info, - const std::string& bluetooth_mac_address, - const ByteArray& uwb_address, - WebRtcState web_rtc_state) { - DoInitialize(/*fast_advertisement=*/false, version, pcp, service_id_hash, - endpoint_id, endpoint_info, bluetooth_mac_address, uwb_address, - web_rtc_state); -} - -BleAdvertisement::BleAdvertisement(Version version, Pcp pcp, - const std::string& endpoint_id, - const ByteArray& endpoint_info, - const ByteArray& uwb_address) { - DoInitialize(/*fast_advertisement=*/true, version, pcp, {}, endpoint_id, - endpoint_info, {}, uwb_address, WebRtcState::kUndefined); -} - -void BleAdvertisement::DoInitialize(bool fast_advertisement, Version version, - Pcp pcp, const ByteArray& service_id_hash, - const std::string& endpoint_id, - const ByteArray& endpoint_info, - const std::string& bluetooth_mac_address, - const ByteArray& uwb_address, - WebRtcState web_rtc_state) { - fast_advertisement_ = fast_advertisement; - if (!fast_advertisement_) { - if (service_id_hash.size() != kServiceIdHashLength) return; - } - int max_endpoint_info_length = - fast_advertisement_ ? kMaxFastEndpointInfoLength : kMaxEndpointInfoLength; - if (version != Version::kV1 || endpoint_id.empty() || - endpoint_id.length() != kEndpointIdLength || - endpoint_info.size() > max_endpoint_info_length) { - return; - } - - switch (pcp) { - case Pcp::kP2pCluster: // Fall through - case Pcp::kP2pStar: // Fall through - case Pcp::kP2pPointToPoint: - break; - default: - return; - } - - version_ = version; - pcp_ = pcp; - service_id_hash_ = service_id_hash; - endpoint_id_ = endpoint_id; - endpoint_info_ = endpoint_info; - uwb_address_ = uwb_address; - if (!fast_advertisement_) { - if (!BluetoothUtils::FromString(bluetooth_mac_address).Empty()) { - bluetooth_mac_address_ = bluetooth_mac_address; - } - - web_rtc_state_ = web_rtc_state; - } -} - -BleAdvertisement::BleAdvertisement(bool fast_advertisement, - const ByteArray& ble_advertisement_bytes) { - fast_advertisement_ = fast_advertisement; - - if (ble_advertisement_bytes.Empty()) { - NEARBY_LOG(ERROR, - "Cannot deserialize BleAdvertisement: null bytes passed in."); - return; - } - - int min_advertisement_length = fast_advertisement_ - ? kMinFastAdvertisementLength - : kMinAdvertisementLength; - - if (ble_advertisement_bytes.size() < min_advertisement_length) { - NEARBY_LOG(ERROR, - "Cannot deserialize BleAdvertisement: expecting min %d raw " - "bytes, got %" PRIu64, - kMinAdvertisementLength, ble_advertisement_bytes.size()); - return; - } - - ByteArray advertisement_bytes{ble_advertisement_bytes}; - BaseInputStream base_input_stream{advertisement_bytes}; - // The first 1 byte is supposed to be the version and pcp. - auto version_and_pcp_byte = static_cast(base_input_stream.ReadUint8()); - // The upper 3 bits are supposed to be the version. - version_ = - static_cast((version_and_pcp_byte & kVersionBitmask) >> 5); - if (version_ != Version::kV1) { - NEARBY_LOG(INFO, - "Cannot deserialize BleAdvertisement: unsupported Version %d", - version_); - return; - } - // The lower 5 bits are supposed to be the Pcp. - pcp_ = static_cast(version_and_pcp_byte & kPcpBitmask); - switch (pcp_) { - case Pcp::kP2pCluster: // Fall through - case Pcp::kP2pStar: // Fall through - case Pcp::kP2pPointToPoint: - break; - default: - NEARBY_LOG(INFO, - "Cannot deserialize BleAdvertisement: uunsupported V1 PCP %d", - pcp_); - } - - // The next 3 bytes are supposed to be the service_id_hash if not fast - // advertisment. - if (!fast_advertisement_) - service_id_hash_ = base_input_stream.ReadBytes(kServiceIdHashLength); - - // The next 4 bytes are supposed to be the endpoint_id. - endpoint_id_ = std::string{base_input_stream.ReadBytes(kEndpointIdLength)}; - - // The next 1 byte is supposed to be the length of the endpoint_info. - std::uint32_t expected_endpoint_info_length = base_input_stream.ReadUint8(); - - // The next x bytes are the endpoint info. (Max length is 131 bytes or 17 - // bytes as fast_advertisement being true). - endpoint_info_ = base_input_stream.ReadBytes(expected_endpoint_info_length); - const int max_endpoint_info_length = - fast_advertisement_ ? kMaxFastEndpointInfoLength : kMaxEndpointInfoLength; - if (endpoint_info_.Empty() || - endpoint_info_.size() != expected_endpoint_info_length || - endpoint_info_.size() > max_endpoint_info_length) { - NEARBY_LOG(INFO, - "Cannot deserialize BleAdvertisement(fast advertisement=%d): " - "expected endpointInfo to be %d bytes, got %" PRIu64, - fast_advertisement_, expected_endpoint_info_length, - endpoint_info_.size()); - - // Clear enpoint_id for validity. - endpoint_id_.clear(); - return; - } - - // The next 6 bytes are the bluetooth mac address if not fast advertisment. - if (!fast_advertisement_) { - auto bluetooth_mac_address_bytes = - base_input_stream.ReadBytes(BluetoothUtils::kBluetoothMacAddressLength); - bluetooth_mac_address_ = - BluetoothUtils::ToString(bluetooth_mac_address_bytes); - } - - // The next 1 byte is supposed to be the length of the uwb_address. If the - // next byte is not available then it should be a fast advertisement and skip - // it for remaining bytes. - if (base_input_stream.IsAvailable(1)) { - std::uint32_t expected_uwb_address_length = base_input_stream.ReadUint8(); - // If the length of uwb_address is not zero, then retrieve it. - if (expected_uwb_address_length != 0) { - uwb_address_ = base_input_stream.ReadBytes(expected_uwb_address_length); - if (uwb_address_.Empty() || - uwb_address_.size() != expected_uwb_address_length) { - NEARBY_LOG(INFO, - "Cannot deserialize BleAdvertisement: " - "expected uwbAddress size to be %d bytes, got %" PRIu64, - expected_uwb_address_length, uwb_address_.size()); - - // Clear enpoint_id for validity. - endpoint_id_.clear(); - return; - } - } - - // The next 1 byte is extra field. - if (!fast_advertisement_) { - if (base_input_stream.IsAvailable(kExtraFieldLength)) { - auto extra_field = static_cast(base_input_stream.ReadUint8()); - web_rtc_state_ = (extra_field & kWebRtcConnectableFlagBitmask) == 1 - ? WebRtcState::kConnectable - : WebRtcState::kUnconnectable; - } - } - } - - base_input_stream.Close(); -} - -BleAdvertisement::operator ByteArray() const { - if (!IsValid()) { - return ByteArray(); - } - - // The first 3 bits are the Version. - char version_and_pcp_byte = - (static_cast(version_) << 5) & kVersionBitmask; - // The next 5 bits are the Pcp. - version_and_pcp_byte |= static_cast(pcp_) & kPcpBitmask; - - std::string out; - if (fast_advertisement_) { - // clang-format off - out = absl::StrCat(std::string(1, version_and_pcp_byte), - endpoint_id_, - std::string(1, endpoint_info_.size()), - std::string(endpoint_info_)); - // clang-format on - } else { - // clang-format off - out = absl::StrCat(std::string(1, version_and_pcp_byte), - std::string(service_id_hash_), - endpoint_id_, - std::string(1, endpoint_info_.size()), - std::string(endpoint_info_)); - // clang-format on - - // The next 6 bytes are the bluetooth mac address. If bluetooth_mac_address - // is invalid or empty, we get back a empty byte array. - auto bluetooth_mac_address_bytes{ - BluetoothUtils::FromString(bluetooth_mac_address_)}; - if (!bluetooth_mac_address_bytes.Empty()) { - absl::StrAppend(&out, std::string(bluetooth_mac_address_bytes)); - } - } - - // The next bytes are UWB address field. - if (!uwb_address_.Empty()) { - absl::StrAppend(&out, std::string(1, uwb_address_.size())); - absl::StrAppend(&out, std::string(uwb_address_)); - } else if (!fast_advertisement_) { - // Write UWB address with length 0 to be able to read the next field when - // decode. - absl::StrAppend(&out, std::string(1, uwb_address_.size())); - } - - // The next 1 byte is extra field. - if (!fast_advertisement_) { - int web_rtc_connectable_flag = - (web_rtc_state_ == WebRtcState::kConnectable) ? 1 : 0; - char extra_field_byte = static_cast(web_rtc_connectable_flag) & - kWebRtcConnectableFlagBitmask; - absl::StrAppend(&out, std::string(1, extra_field_byte)); - } - - return ByteArray(std::move(out)); -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/ble_advertisement.h b/cpp/core_v2/internal/ble_advertisement.h deleted file mode 100644 index 1e7edcdb..00000000 --- a/cpp/core_v2/internal/ble_advertisement.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef CORE_V2_INTERNAL_BLE_ADVERTISEMENT_H_ -#define CORE_V2_INTERNAL_BLE_ADVERTISEMENT_H_ - -#include "core_v2/internal/base_pcp_handler.h" -#include "core_v2/internal/pcp.h" -#include "platform_v2/base/bluetooth_utils.h" -#include "platform_v2/base/byte_array.h" - -namespace location { -namespace nearby { -namespace connections { - -// Represents the format of the Connections Ble Advertisement used in -// Advertising + Discovery. -// -//

[VERSION][PCP][SERVICE_ID_HASH][ENDPOINT_ID][ENDPOINT_INFO_SIZE] -// [ENDPOINT_INFO][BLUETOOTH_MAC][UWB_ADDRESS_SIZE][UWB_ADDRESS][EXTRA_FIELD] -// -//

The fast version of this advertisement simply omits SERVICE_ID_HASH and -// the Bluetooth MAC address. -// -//

See go/connections-ble-advertisement for more information. -class BleAdvertisement { - public: - // Versions of the BleAdvertisement. - enum class Version { - kUndefined = 0, - kV1 = 1, - // Version is only allocated 3 bits in the BleAdvertisement, so this - // can never go beyond V7. - }; - - static constexpr int kVersionAndPcpLength = 1; - static constexpr int kVersionBitmask = 0x0E0; - static constexpr int kPcpBitmask = 0x01F; - static constexpr int kServiceIdHashLength = 3; - static constexpr int kEndpointIdLength = 4; - static constexpr int kEndpointInfoSizeLength = 1; - static constexpr int kBluetoothMacAddressLength = - BluetoothUtils::kBluetoothMacAddressLength; - static constexpr int kUwbAddressSizeLength = 1; - static constexpr int kExtraFieldLength = 1; - static constexpr int kEndpointInfoLengthBitmask = 0x0FF; - static constexpr int kWebRtcConnectableFlagBitmask = 0x01; - static constexpr int kMinAdvertisementLength = - kVersionAndPcpLength + kServiceIdHashLength + kEndpointIdLength + - kEndpointInfoSizeLength + kBluetoothMacAddressLength; - - // The difference between normal and fast advertisements is that the fast one - // omits the SERVICE_ID_HASH and Bluetooth MAC address. This is done to save - // space. - static constexpr int kMinFastAdvertisementLength = kMinAdvertisementLength - - kServiceIdHashLength - - kBluetoothMacAddressLength; - static constexpr int kMaxEndpointInfoLength = 131; - static constexpr int kMaxFastEndpointInfoLength = 17; - - BleAdvertisement() = default; - BleAdvertisement(Version version, Pcp pcp, const std::string& endpoint_id, - const ByteArray& endpoint_info, - const ByteArray& uwb_address); - BleAdvertisement(Version version, Pcp pcp, const ByteArray& service_id_hash, - const std::string& endpoint_id, - const ByteArray& endpoint_info, - const std::string& bluetooth_mac_address, - const ByteArray& uwb_address, - WebRtcState web_rtc_state); - BleAdvertisement(bool fast_advertisement, - const ByteArray& ble_advertisement_bytes); - BleAdvertisement(const BleAdvertisement&) = default; - BleAdvertisement& operator=(const BleAdvertisement&) = default; - BleAdvertisement(BleAdvertisement&&) = default; - BleAdvertisement& operator=(BleAdvertisement&&) = default; - ~BleAdvertisement() = default; - - explicit operator ByteArray() const; - - bool IsValid() const { return !endpoint_id_.empty(); } - bool IsFastAdvertisement() const { return fast_advertisement_; } - Version GetVersion() const { return version_; } - Pcp GetPcp() const { return pcp_; } - ByteArray GetServiceIdHash() const { return service_id_hash_; } - std::string GetEndpointId() const { return endpoint_id_; } - ByteArray GetEndpointInfo() const { return endpoint_info_; } - std::string GetBluetoothMacAddress() const { return bluetooth_mac_address_; } - ByteArray GetUwbAddress() const { return uwb_address_; } - WebRtcState GetWebRtcState() const { return web_rtc_state_; } - - private: - void DoInitialize(bool fast_advertisement, Version version, Pcp pcp, - const ByteArray& service_id_hash, - const std::string& endpoint_id, - const ByteArray& endpoint_info, - const std::string& bluetooth_mac_address, - const ByteArray& uwb_address, WebRtcState web_rtc_state); - - bool fast_advertisement_ = false; - Version version_{Version::kUndefined}; - Pcp pcp_{Pcp::kUnknown}; - ByteArray service_id_hash_; - std::string endpoint_id_; - ByteArray endpoint_info_; - std::string bluetooth_mac_address_; - // TODO(b/169550050): Define UWB address field. - ByteArray uwb_address_; - WebRtcState web_rtc_state_{WebRtcState::kUndefined}; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_BLE_ADVERTISEMENT_H_ diff --git a/cpp/core_v2/internal/ble_advertisement_test.cc b/cpp/core_v2/internal/ble_advertisement_test.cc deleted file mode 100644 index 42e4b978..00000000 --- a/cpp/core_v2/internal/ble_advertisement_test.cc +++ /dev/null @@ -1,477 +0,0 @@ -#include "core_v2/internal/ble_advertisement.h" - -#include "core_v2/internal/base_pcp_handler.h" -#include "gtest/gtest.h" - -namespace location { -namespace nearby { -namespace connections { -namespace { - -constexpr BleAdvertisement::Version kVersion = BleAdvertisement::Version::kV1; -constexpr Pcp kPcp = Pcp::kP2pCluster; -constexpr absl::string_view kServiceIdHashBytes{"\x0a\x0b\x0c"}; -constexpr absl::string_view kEndpointId{"AB12"}; -constexpr absl::string_view kEndpointName{ - "How much wood can a woodchuck chuck if a wood chuck would chuck wood?"}; -constexpr absl::string_view kFastAdvertisementEndpointName{"Fast Advertise"}; -constexpr absl::string_view kBluetoothMacAddress{"00:00:E6:88:64:13"}; -constexpr WebRtcState kWebRtcState = WebRtcState::kConnectable; - -// TODO(b/169550050): Implement UWBAddress. -TEST(BleAdvertisementTest, ConstructionWorks) { - ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; - ByteArray endpoint_info{std::string(kEndpointName)}; - BleAdvertisement ble_advertisement{kVersion, - kPcp, - service_id_hash, - std::string(kEndpointId), - endpoint_info, - std::string(kBluetoothMacAddress), - ByteArray{}, - kWebRtcState}; - - EXPECT_TRUE(ble_advertisement.IsValid()); - EXPECT_FALSE(ble_advertisement.IsFastAdvertisement()); - EXPECT_EQ(kVersion, ble_advertisement.GetVersion()); - EXPECT_EQ(kPcp, ble_advertisement.GetPcp()); - EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash()); - EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId()); - EXPECT_EQ(endpoint_info, ble_advertisement.GetEndpointInfo()); - EXPECT_EQ(kBluetoothMacAddress, ble_advertisement.GetBluetoothMacAddress()); - EXPECT_EQ(kWebRtcState, ble_advertisement.GetWebRtcState()); -} - -TEST(BleAdvertisementTest, ConstructionWorksForFastAdvertisement) { - ByteArray fast_endpoint_info{std::string(kFastAdvertisementEndpointName)}; - BleAdvertisement ble_advertisement{kVersion, - kPcp, - std::string(kEndpointId), - fast_endpoint_info, - ByteArray{}}; - - EXPECT_TRUE(ble_advertisement.IsValid()); - EXPECT_TRUE(ble_advertisement.IsFastAdvertisement()); - EXPECT_EQ(kVersion, ble_advertisement.GetVersion()); - EXPECT_EQ(kPcp, ble_advertisement.GetPcp()); - EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId()); - EXPECT_EQ(fast_endpoint_info, ble_advertisement.GetEndpointInfo()); - EXPECT_EQ(WebRtcState::kUndefined, ble_advertisement.GetWebRtcState()); -} - -TEST(BleAdvertisementTest, ConstructionWorksWithEmptyEndpointInfo) { - ByteArray empty_endpoint_info; - - ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; - BleAdvertisement ble_advertisement{kVersion, - kPcp, - service_id_hash, - std::string(kEndpointId), - empty_endpoint_info, - std::string(kBluetoothMacAddress), - ByteArray{}, - kWebRtcState}; - - EXPECT_TRUE(ble_advertisement.IsValid()); - EXPECT_FALSE(ble_advertisement.IsFastAdvertisement()); - EXPECT_EQ(kVersion, ble_advertisement.GetVersion()); - EXPECT_EQ(kPcp, ble_advertisement.GetPcp()); - EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash()); - EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId()); - EXPECT_EQ(empty_endpoint_info, ble_advertisement.GetEndpointInfo()); - EXPECT_EQ(kBluetoothMacAddress, ble_advertisement.GetBluetoothMacAddress()); - EXPECT_EQ(kWebRtcState, ble_advertisement.GetWebRtcState()); -} - -TEST(BleAdvertisementTest, - ConstructionWorksWithEmptyEndpointInfoForFastAdvertisement) { - ByteArray empty_endpoint_info; - - BleAdvertisement ble_advertisement{kVersion, - kPcp, - std::string(kEndpointId), - empty_endpoint_info, - ByteArray{}}; - - EXPECT_TRUE(ble_advertisement.IsValid()); - EXPECT_TRUE(ble_advertisement.IsFastAdvertisement()); - EXPECT_EQ(kVersion, ble_advertisement.GetVersion()); - EXPECT_EQ(kPcp, ble_advertisement.GetPcp()); - EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId()); - EXPECT_EQ(empty_endpoint_info, ble_advertisement.GetEndpointInfo()); - EXPECT_EQ(WebRtcState::kUndefined, ble_advertisement.GetWebRtcState()); -} - -TEST(BleAdvertisementTest, ConstructionWorksWithEmojiEndpointInfo) { - ByteArray emoji_endpoint_info{std::string("\u0001F450 \u0001F450")}; - - ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; - BleAdvertisement ble_advertisement{kVersion, - kPcp, - service_id_hash, - std::string(kEndpointId), - emoji_endpoint_info, - std::string(kBluetoothMacAddress), - ByteArray{}, - kWebRtcState}; - - EXPECT_TRUE(ble_advertisement.IsValid()); - EXPECT_FALSE(ble_advertisement.IsFastAdvertisement()); - EXPECT_EQ(kVersion, ble_advertisement.GetVersion()); - EXPECT_EQ(kPcp, ble_advertisement.GetPcp()); - EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash()); - EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId()); - EXPECT_EQ(emoji_endpoint_info, ble_advertisement.GetEndpointInfo()); - EXPECT_EQ(kBluetoothMacAddress, ble_advertisement.GetBluetoothMacAddress()); - EXPECT_EQ(kWebRtcState, ble_advertisement.GetWebRtcState()); -} - -TEST(BleAdvertisementTest, - ConstructionWorksWithEmojiEndpointInfoForFastAdvertisement) { - ByteArray emoji_endpoint_info{std::string("\u0001F450 \u0001F450")}; - - BleAdvertisement ble_advertisement{kVersion, - kPcp, - std::string(kEndpointId), - emoji_endpoint_info, - ByteArray{}}; - - EXPECT_TRUE(ble_advertisement.IsValid()); - EXPECT_TRUE(ble_advertisement.IsFastAdvertisement()); - EXPECT_EQ(kVersion, ble_advertisement.GetVersion()); - EXPECT_EQ(kPcp, ble_advertisement.GetPcp()); - EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId()); - EXPECT_EQ(emoji_endpoint_info, ble_advertisement.GetEndpointInfo()); - EXPECT_EQ(WebRtcState::kUndefined, ble_advertisement.GetWebRtcState()); -} - -TEST(BleAdvertisementTest, ConstructionFailsWithLongEndpointInfo) { - std::string long_endpoint_name(BleAdvertisement::kMaxEndpointInfoLength + 1, - 'x'); - ByteArray long_endpoint_info{long_endpoint_name}; - - ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; - BleAdvertisement ble_advertisement{kVersion, - kPcp, - service_id_hash, - std::string(kEndpointId), - long_endpoint_info, - std::string(kBluetoothMacAddress), - ByteArray{}, - kWebRtcState}; - - EXPECT_FALSE(ble_advertisement.IsValid()); -} - -TEST(BleAdvertisementTest, - ConstructionFailsWithLongEndpointInfoForFastAdvertisement) { - std::string long_endpoint_name( - BleAdvertisement::kMaxFastEndpointInfoLength + 1, 'x'); - ByteArray long_endpoint_info{long_endpoint_name}; - - BleAdvertisement ble_advertisement{kVersion, - kPcp, - std::string(kEndpointId), - long_endpoint_info, - ByteArray{}}; - - EXPECT_FALSE(ble_advertisement.IsValid()); -} - -TEST(BleAdvertisementTest, ConstructionFailsWithBadVersion) { - auto bad_version = static_cast(666); - - ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; - ByteArray endpoint_info{std::string(kEndpointName)}; - BleAdvertisement ble_advertisement{bad_version, - kPcp, - service_id_hash, - std::string(kEndpointId), - endpoint_info, - std::string(kBluetoothMacAddress), - ByteArray{}, - kWebRtcState}; - - EXPECT_FALSE(ble_advertisement.IsValid()); -} - -TEST(BleAdvertisementTest, - ConstructionFailsWithBadVersionForFastAdvertisement) { - auto bad_version = static_cast(666); - - ByteArray fast_endpoint_info{std::string(kFastAdvertisementEndpointName)}; - BleAdvertisement ble_advertisement{bad_version, - kPcp, - std::string(kEndpointId), - fast_endpoint_info, - ByteArray{}}; - - EXPECT_FALSE(ble_advertisement.IsValid()); -} - -TEST(BleAdvertisementTest, ConstructionFailsWithBadPCP) { - auto bad_pcp = static_cast(666); - - ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; - ByteArray endpoint_info{std::string(kEndpointName)}; - BleAdvertisement ble_advertisement{kVersion, - bad_pcp, - service_id_hash, - std::string(kEndpointId), - endpoint_info, - std::string(kBluetoothMacAddress), - ByteArray{}, - kWebRtcState}; - - EXPECT_FALSE(ble_advertisement.IsValid()); -} - -TEST(BleAdvertisementTest, ConstructionFailsWithBadPCPForFastAdvertisement) { - auto bad_pcp = static_cast(666); - - ByteArray fast_endpoint_info{std::string(kFastAdvertisementEndpointName)}; - BleAdvertisement ble_advertisement{kVersion, - bad_pcp, - std::string(kEndpointId), - fast_endpoint_info, - ByteArray{}}; - - EXPECT_FALSE(ble_advertisement.IsValid()); -} - -TEST(BleAdvertisementTest, ConstructionSucceedsWithEmptyBluetoothMacAddress) { - std::string empty_bluetooth_mac_address = ""; - - ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; - ByteArray endpoint_info{std::string(kEndpointName)}; - BleAdvertisement ble_advertisement{kVersion, - kPcp, - service_id_hash, - std::string(kEndpointId), - endpoint_info, - empty_bluetooth_mac_address, - ByteArray{}, - kWebRtcState}; - - EXPECT_TRUE(ble_advertisement.IsValid()); -} - -TEST(BleAdvertisementTest, ConstructionSucceedsWithInvalidBluetoothMacAddress) { - std::string bad_bluetooth_mac_address = "022:00"; - - ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; - ByteArray endpoint_info{std::string(kEndpointName)}; - BleAdvertisement ble_advertisement{kVersion, - kPcp, - service_id_hash, - std::string(kEndpointId), - endpoint_info, - bad_bluetooth_mac_address, - ByteArray{}, - kWebRtcState}; - - EXPECT_TRUE(ble_advertisement.IsValid()); - EXPECT_EQ(kVersion, ble_advertisement.GetVersion()); - EXPECT_EQ(kPcp, ble_advertisement.GetPcp()); - EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash()); - EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId()); - EXPECT_EQ(endpoint_info, ble_advertisement.GetEndpointInfo()); - EXPECT_TRUE(ble_advertisement.GetBluetoothMacAddress().empty()); - EXPECT_EQ(kWebRtcState, ble_advertisement.GetWebRtcState()); -} - -TEST(BleAdvertisementTest, ConstructionFromBytesWorks) { - // Serialize good data into a good Ble Advertisement. - ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; - ByteArray endpoint_info{std::string(kEndpointName)}; - BleAdvertisement org_ble_advertisement{kVersion, - kPcp, - service_id_hash, - std::string(kEndpointId), - endpoint_info, - std::string(kBluetoothMacAddress), - ByteArray{}, - kWebRtcState}; - ByteArray ble_advertisement_bytes(org_ble_advertisement); - - BleAdvertisement ble_advertisement{false, ble_advertisement_bytes}; - - EXPECT_TRUE(ble_advertisement.IsValid()); - EXPECT_FALSE(ble_advertisement.IsFastAdvertisement()); - EXPECT_EQ(kVersion, ble_advertisement.GetVersion()); - EXPECT_EQ(kPcp, ble_advertisement.GetPcp()); - EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash()); - EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId()); - EXPECT_EQ(endpoint_info, ble_advertisement.GetEndpointInfo()); - EXPECT_EQ(kBluetoothMacAddress, ble_advertisement.GetBluetoothMacAddress()); - EXPECT_EQ(kWebRtcState, ble_advertisement.GetWebRtcState()); -} - -TEST(BleAdvertisementTest, ConstructionFromBytesWorksForFastAdvertisement) { - // Serialize good data into a good Ble Advertisement. - ByteArray fast_endpoint_info{std::string(kFastAdvertisementEndpointName)}; - BleAdvertisement org_ble_advertisement{kVersion, - kPcp, - std::string(kEndpointId), - fast_endpoint_info, - ByteArray{}}; - ByteArray ble_advertisement_bytes(org_ble_advertisement); - - BleAdvertisement ble_advertisement{true, ble_advertisement_bytes}; - - EXPECT_TRUE(ble_advertisement.IsValid()); - EXPECT_TRUE(ble_advertisement.IsFastAdvertisement()); - EXPECT_EQ(kVersion, ble_advertisement.GetVersion()); - EXPECT_EQ(kPcp, ble_advertisement.GetPcp()); - EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId()); - EXPECT_EQ(fast_endpoint_info, ble_advertisement.GetEndpointInfo()); - EXPECT_EQ(WebRtcState::kUndefined, ble_advertisement.GetWebRtcState()); -} - -// Bytes at the end should be ignored so that they can be used as reserve bytes -// in the future. -TEST(BleAdvertisementTest, ConstructionFromLongLengthBytesWorks) { - // Serialize good data into a good Ble Advertisement. - ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; - ByteArray endpoint_info{std::string(kEndpointName)}; - BleAdvertisement ble_advertisement{kVersion, - kPcp, - service_id_hash, - std::string(kEndpointId), - endpoint_info, - std::string(kBluetoothMacAddress), - ByteArray{}, - kWebRtcState}; - ByteArray ble_advertisement_bytes(ble_advertisement); - - // Add bytes to the end of the valid Ble advertisement. - ByteArray long_ble_advertisement_bytes( - BleAdvertisement::kMinAdvertisementLength + 1000); - ASSERT_LE(ble_advertisement_bytes.size(), - long_ble_advertisement_bytes.size()); - memcpy(long_ble_advertisement_bytes.data(), ble_advertisement_bytes.data(), - ble_advertisement_bytes.size()); - - BleAdvertisement long_ble_advertisement{false, long_ble_advertisement_bytes}; - - EXPECT_TRUE(long_ble_advertisement.IsValid()); - EXPECT_EQ(kVersion, long_ble_advertisement.GetVersion()); - EXPECT_EQ(kPcp, long_ble_advertisement.GetPcp()); - EXPECT_EQ(service_id_hash, long_ble_advertisement.GetServiceIdHash()); - EXPECT_EQ(kEndpointId, long_ble_advertisement.GetEndpointId()); - EXPECT_EQ(endpoint_info, long_ble_advertisement.GetEndpointInfo()); - EXPECT_EQ(kBluetoothMacAddress, - long_ble_advertisement.GetBluetoothMacAddress()); - EXPECT_EQ(kWebRtcState, ble_advertisement.GetWebRtcState()); -} - -TEST(BleAdvertisementTest, ConstructionFromNullBytesFails) { - BleAdvertisement ble_advertisement{false, ByteArray{}}; - - EXPECT_FALSE(ble_advertisement.IsValid()); -} - -TEST(BleAdvertisementTest, ConstructionFromNullBytesFailsForFastAdvertisement) { - BleAdvertisement ble_advertisement{true, ByteArray{}}; - - EXPECT_FALSE(ble_advertisement.IsValid()); -} - -TEST(BleAdvertisementTest, ConstructionFromShortLengthBytesFails) { - // Serialize good data into a good Ble Advertisement. - ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; - ByteArray endpoint_info{std::string(kEndpointName)}; - BleAdvertisement ble_advertisement{kVersion, - kPcp, - service_id_hash, - std::string(kEndpointId), - endpoint_info, - std::string(kBluetoothMacAddress), - ByteArray{}, - kWebRtcState}; - ByteArray ble_advertisement_bytes(ble_advertisement); - - // Shorten the valid Ble Advertisement. - ByteArray short_ble_advertisement_bytes{ - ble_advertisement_bytes.data(), - BleAdvertisement::kMinAdvertisementLength - 1}; - - BleAdvertisement short_ble_advertisement{false, - short_ble_advertisement_bytes}; - - EXPECT_FALSE(short_ble_advertisement.IsValid()); -} - -TEST(BleAdvertisementTest, - ConstructionFromShortLengthBytesFailsForFastAdvertisement) { - // Serialize good data into a good Ble Advertisement. - ByteArray fast_endpoint_info{std::string(kFastAdvertisementEndpointName)}; - BleAdvertisement ble_advertisement{kVersion, - kPcp, - std::string(kEndpointId), - fast_endpoint_info, - ByteArray{}}; - ByteArray ble_advertisement_bytes(ble_advertisement); - - // Shorten the valid Ble Advertisement. - ByteArray short_ble_advertisement_bytes{ - ble_advertisement_bytes.data(), - BleAdvertisement::kMinAdvertisementLength - 1}; - - BleAdvertisement short_ble_advertisement{true, short_ble_advertisement_bytes}; - - EXPECT_FALSE(short_ble_advertisement.IsValid()); -} - -TEST(BleAdvertisementTest, - ConstructionFromByesWithWrongEndpointInfoLengthFails) { - // Serialize good data into a good Ble Advertisement. - ByteArray service_id_hash{std::string(kServiceIdHashBytes)}; - ByteArray endpoint_info{std::string(kEndpointName)}; - BleAdvertisement ble_advertisement{kVersion, - kPcp, - service_id_hash, - std::string(kEndpointId), - endpoint_info, - std::string(kBluetoothMacAddress), - ByteArray{}, - kWebRtcState}; - ByteArray ble_advertisement_bytes(ble_advertisement); - - // Corrupt the EndpointNameLength bits. - std::string corrupt_ble_advertisement_string(ble_advertisement_bytes); - corrupt_ble_advertisement_string[8] ^= 0x0FF; - ByteArray corrupt_ble_advertisement_bytes(corrupt_ble_advertisement_string); - - BleAdvertisement corrupt_ble_advertisement{false, - corrupt_ble_advertisement_bytes}; - - EXPECT_FALSE(corrupt_ble_advertisement.IsValid()); -} - -TEST(BleAdvertisementTest, - ConstructionFromByesWithWrongEndpointInfoLengthFailsForFastAdvertisement) { - // Serialize good data into a good Ble Advertisement. - ByteArray fast_endpoint_info{std::string(kFastAdvertisementEndpointName)}; - BleAdvertisement ble_advertisement{kVersion, - kPcp, - std::string(kEndpointId), - fast_endpoint_info, - ByteArray{}}; - ByteArray ble_advertisement_bytes = ByteArray(ble_advertisement); - - // Corrupt the EndpointInfoLength bits. - std::string corrupt_ble_advertisement_string(ble_advertisement_bytes); - corrupt_ble_advertisement_string[5] ^= 0x0FF; - ByteArray corrupt_ble_advertisement_bytes(corrupt_ble_advertisement_string); - - BleAdvertisement corrupt_ble_advertisement{true, - corrupt_ble_advertisement_bytes}; - - EXPECT_FALSE(corrupt_ble_advertisement.IsValid()); -} - -} // namespace -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/ble_endpoint_channel.cc b/cpp/core_v2/internal/ble_endpoint_channel.cc deleted file mode 100644 index aba332d0..00000000 --- a/cpp/core_v2/internal/ble_endpoint_channel.cc +++ /dev/null @@ -1,45 +0,0 @@ -#include "core_v2/internal/ble_endpoint_channel.h" - -#include - -#include "platform_v2/public/ble.h" -#include "platform_v2/public/logging.h" - -namespace location { -namespace nearby { -namespace connections { - -namespace { - -OutputStream* GetOutputStreamOrNull(BleSocket& socket) { - if (socket.GetRemotePeripheral().IsValid()) return &socket.GetOutputStream(); - return nullptr; -} - -InputStream* GetInputStreamOrNull(BleSocket& socket) { - if (socket.GetRemotePeripheral().IsValid()) return &socket.GetInputStream(); - return nullptr; -} - -} // namespace - -BleEndpointChannel::BleEndpointChannel(const std::string& channel_name, - BleSocket socket) - : BaseEndpointChannel(channel_name, GetInputStreamOrNull(socket), - GetOutputStreamOrNull(socket)), - ble_socket_(std::move(socket)) {} - -proto::connections::Medium BleEndpointChannel::GetMedium() const { - return proto::connections::Medium::BLE; -} - -void BleEndpointChannel::CloseImpl() { - auto status = ble_socket_.Close(); - if (!status.Ok()) { - NEARBY_LOG(INFO, "Failed to close Ble socket: exception=%d", status.value); - } -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/ble_endpoint_channel.h b/cpp/core_v2/internal/ble_endpoint_channel.h deleted file mode 100644 index 74d68993..00000000 --- a/cpp/core_v2/internal/ble_endpoint_channel.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef CORE_V2_INTERNAL_BLE_ENDPOINT_CHANNEL_H_ -#define CORE_V2_INTERNAL_BLE_ENDPOINT_CHANNEL_H_ - -#include "core_v2/internal/base_endpoint_channel.h" -#include "platform_v2/public/ble.h" -#include "proto/connections_enums.pb.h" - -namespace location { -namespace nearby { -namespace connections { - -class BleEndpointChannel final : public BaseEndpointChannel { - public: - // Creates both outgoing and incoming Ble channels. - BleEndpointChannel(const std::string& channel_name, BleSocket socket); - - proto::connections::Medium GetMedium() const override; - - private: - void CloseImpl() override; - - BleSocket ble_socket_; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_BLE_ENDPOINT_CHANNEL_H_ diff --git a/cpp/core_v2/internal/bluetooth_device_name.cc b/cpp/core_v2/internal/bluetooth_device_name.cc deleted file mode 100644 index 374fd186..00000000 --- a/cpp/core_v2/internal/bluetooth_device_name.cc +++ /dev/null @@ -1,204 +0,0 @@ -#include "core_v2/internal/bluetooth_device_name.h" - -#include - -#include -#include - -#include "platform_v2/base/base64_utils.h" -#include "platform_v2/base/base_input_stream.h" -#include "platform_v2/public/logging.h" -#include "absl/strings/escaping.h" -#include "absl/strings/str_cat.h" - -namespace location { -namespace nearby { -namespace connections { - -BluetoothDeviceName::BluetoothDeviceName(Version version, Pcp pcp, - absl::string_view endpoint_id, - const ByteArray& service_id_hash, - const ByteArray& endpoint_info, - const ByteArray& uwb_address, - WebRtcState web_rtc_state) { - if (version != Version::kV1 || endpoint_id.empty() || - endpoint_id.length() != kEndpointIdLength || - service_id_hash.size() != kServiceIdHashLength) { - return; - } - switch (pcp) { - case Pcp::kP2pCluster: // Fall through - case Pcp::kP2pStar: // Fall through - case Pcp::kP2pPointToPoint: - break; - default: - return; - } - - version_ = version; - pcp_ = pcp; - endpoint_id_ = std::string(endpoint_id); - service_id_hash_ = service_id_hash; - endpoint_info_ = endpoint_info; - uwb_address_ = uwb_address; - web_rtc_state_ = web_rtc_state; -} - -BluetoothDeviceName::BluetoothDeviceName( - absl::string_view bluetooth_device_name_string) { - ByteArray bluetooth_device_name_bytes = - Base64Utils::Decode(bluetooth_device_name_string); - - if (bluetooth_device_name_bytes.Empty()) { - NEARBY_LOG( - INFO, - "Cannot deserialize BluetoothDeviceName: failed Base64 decoding of %s", - std::string(bluetooth_device_name_string).c_str()); - return; - } - - if (bluetooth_device_name_bytes.size() < kMinBluetoothDeviceNameLength) { - NEARBY_LOG(INFO, - "Cannot deserialize BluetoothDeviceName: expecting min %d raw " - "bytes, got %" PRIu64, - kMinBluetoothDeviceNameLength, - bluetooth_device_name_bytes.size()); - return; - } - - BaseInputStream base_input_stream{bluetooth_device_name_bytes}; - // The first 1 byte is supposed to be the version and pcp. - auto version_and_pcp_byte = static_cast(base_input_stream.ReadUint8()); - // The upper 3 bits are supposed to be the version. - version_ = - static_cast((version_and_pcp_byte & kVersionBitmask) >> 5); - if (version_ != Version::kV1) { - NEARBY_LOG(INFO, - "Cannot deserialize BluetoothDeviceName: unsupported version=%d", - version_); - return; - } - // The lower 5 bits are supposed to be the Pcp. - pcp_ = static_cast(version_and_pcp_byte & kPcpBitmask); - switch (pcp_) { - case Pcp::kP2pCluster: // Fall through - case Pcp::kP2pStar: // Fall through - case Pcp::kP2pPointToPoint: - break; - default: - NEARBY_LOG( - INFO, "Cannot deserialize BluetoothDeviceName: unsupported V1 PCP %d", - pcp_); - return; - } - - // The next 4 bytes are supposed to be the endpoint_id. - endpoint_id_ = std::string{base_input_stream.ReadBytes(kEndpointIdLength)}; - - // The next 3 bytes are supposed to be the service_id_hash. - service_id_hash_ = base_input_stream.ReadBytes(kServiceIdHashLength); - - - // The next 1 byte is field containning WebRtc state. - auto field_byte = static_cast(base_input_stream.ReadUint8()); - web_rtc_state_ = (field_byte & kWebRtcConnectableFlagBitmask) == 1 - ? WebRtcState::kConnectable - : WebRtcState::kUnconnectable; - - // The next 6 bytes are supposed to be reserved, and can be left - // untouched. - base_input_stream.ReadBytes(kReservedLength); - - // The next 1 byte is supposed to be the length of the endpoint_info. - std::uint32_t expected_endpoint_info_length = base_input_stream.ReadUint8(); - - // The rest bytes are supposed to be the endpoint_info - endpoint_info_ = base_input_stream.ReadBytes(expected_endpoint_info_length); - if (endpoint_info_.Empty() || - endpoint_info_.size() != expected_endpoint_info_length) { - NEARBY_LOG(INFO, - "Cannot deserialize BluetoothDeviceName: expected " - "endpoint info to be %d bytes, got %" PRIu64, - expected_endpoint_info_length, endpoint_info_.size()); - - // Clear enpoint_id for validadity. - endpoint_id_.clear(); - return; - } - - // If the input stream has extra bytes, it's for UWB address. The first byte - // is the address length. It can be 2-byte short address or 8-byte extended - // address. - if (base_input_stream.IsAvailable(1)) { - // The next 1 byte is supposed to be the length of the uwb_address. - std::uint32_t expected_uwb_address_length = base_input_stream.ReadUint8(); - // If the length of usb_address is not zero, then retrieve it. - if (expected_uwb_address_length != 0) { - uwb_address_ = base_input_stream.ReadBytes(expected_uwb_address_length); - if (uwb_address_.Empty() || - uwb_address_.size() != expected_uwb_address_length) { - NEARBY_LOG(INFO, - "Cannot deserialize BluetoothDeviceName: " - "expected uwbAddress size to be %d bytes, got %" PRIu64, - expected_uwb_address_length, uwb_address_.size()); - - // Clear enpoint_id for validadity. - endpoint_id_.clear(); - return; - } - } - } -} - -BluetoothDeviceName::operator std::string() const { - if (!IsValid()) { - return ""; - } - - // The upper 3 bits are the Version. - auto version_and_pcp_byte = static_cast( - (static_cast(Version::kV1) << 5) & kVersionBitmask); - // The lower 5 bits are the PCP. - version_and_pcp_byte |= - static_cast(static_cast(pcp_) & kPcpBitmask); - - // A byte contains WebRtcState state. - int web_rtc_connectable_flag = - (web_rtc_state_ == WebRtcState::kConnectable) ? 1 : 0; - char field_byte = static_cast(web_rtc_connectable_flag) & - kWebRtcConnectableFlagBitmask; - - ByteArray reserved_bytes{kReservedLength}; - - ByteArray usable_endpoint_info(endpoint_info_); - if (endpoint_info_.size() > kMaxEndpointInfoLength) { - NEARBY_LOG(INFO, - "While serializing Advertisement, truncating Endpoint Name %s " - "(%lu bytes) down to %d bytes", - absl::BytesToHexString(endpoint_info_.data()).c_str(), - endpoint_info_.size(), kMaxEndpointInfoLength); - usable_endpoint_info.SetData(endpoint_info_.data(), kMaxEndpointInfoLength); - } - - // clang-format off - std::string out = absl::StrCat(std::string(1, version_and_pcp_byte), - endpoint_id_, - std::string(service_id_hash_), - std::string(1, field_byte), - std::string(reserved_bytes), - std::string(1, usable_endpoint_info.size()), - std::string(usable_endpoint_info)); - // clang-format on - - // If UWB address is available, attach it at the end. - if (!uwb_address_.Empty()) { - absl::StrAppend(&out, std::string(1, uwb_address_.size())); - absl::StrAppend(&out, std::string(uwb_address_)); - } - - return Base64Utils::Encode(ByteArray{std::move(out)}); -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/bluetooth_device_name.h b/cpp/core_v2/internal/bluetooth_device_name.h deleted file mode 100644 index 77de4f53..00000000 --- a/cpp/core_v2/internal/bluetooth_device_name.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef CORE_V2_INTERNAL_BLUETOOTH_DEVICE_NAME_H_ -#define CORE_V2_INTERNAL_BLUETOOTH_DEVICE_NAME_H_ - -#include - -#include "core_v2/internal/base_pcp_handler.h" -#include "core_v2/internal/pcp.h" -#include "platform_v2/base/byte_array.h" -#include "absl/strings/string_view.h" - -namespace location { -namespace nearby { -namespace connections { - -// Represents the format of the Bluetooth device name used in Advertising + -// Discovery. -// -//

See go/nearby-offline-data-interchange-formats for the specification. -class BluetoothDeviceName { - public: - // Versions of the BluetoothDeviceName. - enum class Version { - kUndefined = 0, - kV1 = 1, - // Version is only allocated 3 bits in the BluetoothDeviceName, so this - // can never go beyond V7. - }; - - static constexpr int kServiceIdHashLength = 3; - - BluetoothDeviceName() = default; - BluetoothDeviceName(Version version, Pcp pcp, absl::string_view endpoint_id, - const ByteArray& service_id_hash, - const ByteArray& endpoint_info, - const ByteArray& uwb_address, - WebRtcState web_rtc_state); - explicit BluetoothDeviceName(absl::string_view bluetooth_device_name_string); - BluetoothDeviceName(const BluetoothDeviceName&) = default; - BluetoothDeviceName& operator=(const BluetoothDeviceName&) = default; - BluetoothDeviceName(BluetoothDeviceName&&) = default; - BluetoothDeviceName& operator=(BluetoothDeviceName&&) = default; - ~BluetoothDeviceName() = default; - - explicit operator std::string() const; - - bool IsValid() const { return !endpoint_id_.empty(); } - Version GetVersion() const { return version_; } - Pcp GetPcp() const { return pcp_; } - std::string GetEndpointId() const { return endpoint_id_; } - ByteArray GetServiceIdHash() const { return service_id_hash_; } - ByteArray GetEndpointInfo() const { return endpoint_info_; } - ByteArray GetUwbAddress() const { return uwb_address_; } - WebRtcState GetWebRtcState() const { return web_rtc_state_; } - - private: - static constexpr int kEndpointIdLength = 4; - static constexpr int kReservedLength = 6; - static constexpr int kMaxEndpointInfoLength = 131; - static constexpr int kMinBluetoothDeviceNameLength = 16; - - static constexpr int kVersionBitmask = 0x0E0; - static constexpr int kPcpBitmask = 0x01F; - static constexpr int kEndpointNameLengthBitmask = 0x0FF; - static constexpr int kWebRtcConnectableFlagBitmask = 0x01; - - Version version_{Version::kUndefined}; - Pcp pcp_{Pcp::kUnknown}; - std::string endpoint_id_; - ByteArray service_id_hash_; - ByteArray endpoint_info_; - // TODO(b/169550050): Define UWB address field. - ByteArray uwb_address_; - WebRtcState web_rtc_state_{WebRtcState::kUndefined}; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_BLUETOOTH_DEVICE_NAME_H_ diff --git a/cpp/core_v2/internal/bluetooth_device_name_test.cc b/cpp/core_v2/internal/bluetooth_device_name_test.cc deleted file mode 100644 index a509170e..00000000 --- a/cpp/core_v2/internal/bluetooth_device_name_test.cc +++ /dev/null @@ -1,229 +0,0 @@ -#include "core_v2/internal/bluetooth_device_name.h" - -#include -#include - -#include "platform_v2/base/base64_utils.h" -#include "gtest/gtest.h" - -namespace location { -namespace nearby { -namespace connections { -namespace { - -constexpr BluetoothDeviceName::Version kVersion = - BluetoothDeviceName::Version::kV1; -constexpr Pcp kPcp = Pcp::kP2pCluster; -constexpr absl::string_view kEndPointID{"AB12"}; -constexpr absl::string_view kServiceIDHashBytes{"\x0a\x0b\x0c"}; -constexpr absl::string_view kEndPointName{"RAWK + ROWL!"}; -constexpr WebRtcState kWebRtcState = WebRtcState::kConnectable; - -// TODO(b/169550050): Implement UWBAddress. -TEST(BluetoothDeviceNameTest, ConstructionWorks) { - ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; - ByteArray endpoint_info{std::string(kEndPointName)}; - BluetoothDeviceName bluetooth_device_name{kVersion, - kPcp, - kEndPointID, - service_id_hash, - endpoint_info, - ByteArray{}, - kWebRtcState}; - - EXPECT_TRUE(bluetooth_device_name.IsValid()); - EXPECT_EQ(kVersion, bluetooth_device_name.GetVersion()); - EXPECT_EQ(kPcp, bluetooth_device_name.GetPcp()); - EXPECT_EQ(kEndPointID, bluetooth_device_name.GetEndpointId()); - EXPECT_EQ(service_id_hash, bluetooth_device_name.GetServiceIdHash()); - EXPECT_EQ(endpoint_info, bluetooth_device_name.GetEndpointInfo()); - EXPECT_EQ(kWebRtcState, bluetooth_device_name.GetWebRtcState()); -} - -TEST(BluetoothDeviceNameTest, ConstructionWorksWithEmptyEndpointName) { - ByteArray empty_endpoint_info; - - ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; - BluetoothDeviceName bluetooth_device_name{kVersion, - kPcp, - kEndPointID, - service_id_hash, - empty_endpoint_info, - ByteArray{}, - kWebRtcState}; - - EXPECT_TRUE(bluetooth_device_name.IsValid()); - EXPECT_EQ(kVersion, bluetooth_device_name.GetVersion()); - EXPECT_EQ(kPcp, bluetooth_device_name.GetPcp()); - EXPECT_EQ(kEndPointID, bluetooth_device_name.GetEndpointId()); - EXPECT_EQ(service_id_hash, bluetooth_device_name.GetServiceIdHash()); - EXPECT_EQ(empty_endpoint_info, bluetooth_device_name.GetEndpointInfo()); - EXPECT_EQ(kWebRtcState, bluetooth_device_name.GetWebRtcState()); -} - -TEST(BluetoothDeviceNameTest, ConstructionFailsWithBadVersion) { - auto bad_version = static_cast(666); - - ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; - ByteArray endpoint_info{std::string(kEndPointName)}; - BluetoothDeviceName bluetooth_device_name{bad_version, - kPcp, - kEndPointID, - service_id_hash, - endpoint_info, - ByteArray{}, - kWebRtcState}; - - EXPECT_FALSE(bluetooth_device_name.IsValid()); -} - -TEST(BluetoothDeviceNameTest, ConstructionFailsWithBadPcp) { - auto bad_pcp = static_cast(666); - - ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; - ByteArray endpoint_info{std::string(kEndPointName)}; - BluetoothDeviceName bluetooth_device_name{kVersion, - bad_pcp, - kEndPointID, - service_id_hash, - endpoint_info, - ByteArray{}, - kWebRtcState}; - - EXPECT_FALSE(bluetooth_device_name.IsValid()); -} - -TEST(BluetoothDeviceNameTest, ConstructionFailsWithShortEndpointId) { - std::string short_endpoint_id("AB1"); - - ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; - ByteArray endpoint_info{std::string(kEndPointName)}; - BluetoothDeviceName bluetooth_device_name{kVersion, - kPcp, - short_endpoint_id, - service_id_hash, - endpoint_info, - ByteArray{}, - kWebRtcState}; - - EXPECT_FALSE(bluetooth_device_name.IsValid()); -} - -TEST(BluetoothDeviceNameTest, ConstructionFailsWithLongEndpointId) { - std::string long_endpoint_id("AB12X"); - - ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; - ByteArray endpoint_info{std::string(kEndPointName)}; - BluetoothDeviceName bluetooth_device_name{kVersion, - kPcp, - long_endpoint_id, - service_id_hash, - endpoint_info, - ByteArray{}, - kWebRtcState}; - - EXPECT_FALSE(bluetooth_device_name.IsValid()); -} - -TEST(BluetoothDeviceNameTest, ConstructionFailsWithShortServiceIdHash) { - char short_service_id_hash_bytes[] = "\x0a\x0b"; - - ByteArray short_service_id_hash{short_service_id_hash_bytes}; - ByteArray endpoint_info{std::string(kEndPointName)}; - BluetoothDeviceName bluetooth_device_name{kVersion, - kPcp, - kEndPointID, - short_service_id_hash, - endpoint_info, - ByteArray{}, - kWebRtcState}; - - EXPECT_FALSE(bluetooth_device_name.IsValid()); -} - -TEST(BluetoothDeviceNameTest, ConstructionFailsWithLongServiceIdHash) { - char long_service_id_hash_bytes[] = "\x0a\x0b\x0c\x0d"; - - ByteArray long_service_id_hash{long_service_id_hash_bytes}; - ByteArray endpoint_info{std::string(kEndPointName)}; - BluetoothDeviceName bluetooth_device_name{kVersion, - kPcp, - kEndPointID, - long_service_id_hash, - endpoint_info, - ByteArray{}, - kWebRtcState}; - - EXPECT_FALSE(bluetooth_device_name.IsValid()); -} - -TEST(BluetoothDeviceNameTest, ConstructionFailsWithShortStringLength) { - char bluetooth_device_name_string[] = "X"; - - ByteArray bluetooth_device_name_bytes{bluetooth_device_name_string}; - BluetoothDeviceName bluetooth_device_name{ - Base64Utils::Encode(bluetooth_device_name_bytes)}; - - EXPECT_FALSE(bluetooth_device_name.IsValid()); -} - -TEST(BluetoothDeviceNameTest, ConstructionFailsWithWrongEndpointNameLength) { - // Serialize good data into a good Bluetooth Device Name. - ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; - ByteArray endpoint_info{std::string(kEndPointName)}; - BluetoothDeviceName bluetooth_device_name{kVersion, - kPcp, - kEndPointID, - service_id_hash, - endpoint_info, - ByteArray{}, - kWebRtcState}; - auto bluetooth_device_name_string = std::string(bluetooth_device_name); - - // Base64-decode the good Bluetooth Device Name. - ByteArray bluetooth_device_name_bytes = - Base64Utils::Decode(bluetooth_device_name_string); - // Corrupt the EndpointNameLength bits (120-127) by reversing all of them. - std::string corrupt_string(bluetooth_device_name_bytes.data(), - bluetooth_device_name_bytes.size()); - corrupt_string[15] ^= 0x0FF; - // Base64-encode the corrupted bytes into a corrupt Bluetooth Device Name. - ByteArray corrupt_bluetooth_device_name_bytes{corrupt_string.data(), - corrupt_string.size()}; - std::string corrupt_bluetooth_device_name_string( - Base64Utils::Encode(corrupt_bluetooth_device_name_bytes)); - - // And deserialize the corrupt Bluetooth Device Name. - BluetoothDeviceName corrupt_bluetooth_device_name( - corrupt_bluetooth_device_name_string); - - EXPECT_FALSE(corrupt_bluetooth_device_name.IsValid()); -} - -TEST(BluetoothDeviceNameTest, CanParseGeneratedName) { - ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; - ByteArray endpoint_info{std::string(kEndPointName)}; - // Build name1 from scratch. - BluetoothDeviceName name1{kVersion, - kPcp, - kEndPointID, - service_id_hash, - endpoint_info, - ByteArray{}, - kWebRtcState}; - // Build name2 from string composed from name1. - BluetoothDeviceName name2{std::string(name1)}; - EXPECT_TRUE(name1.IsValid()); - EXPECT_TRUE(name2.IsValid()); - EXPECT_EQ(name1.GetVersion(), name2.GetVersion()); - EXPECT_EQ(name1.GetPcp(), name2.GetPcp()); - EXPECT_EQ(name1.GetEndpointId(), name2.GetEndpointId()); - EXPECT_EQ(name1.GetServiceIdHash(), name2.GetServiceIdHash()); - EXPECT_EQ(name1.GetEndpointInfo(), name2.GetEndpointInfo()); - EXPECT_EQ(name1.GetWebRtcState(), name2.GetWebRtcState()); -} - -} // namespace -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/bluetooth_endpoint_channel.cc b/cpp/core_v2/internal/bluetooth_endpoint_channel.cc deleted file mode 100644 index 1ae5337f..00000000 --- a/cpp/core_v2/internal/bluetooth_endpoint_channel.cc +++ /dev/null @@ -1,45 +0,0 @@ -#include "core_v2/internal/bluetooth_endpoint_channel.h" - -#include - -#include "platform_v2/public/bluetooth_classic.h" -#include "platform_v2/public/logging.h" - -namespace location { -namespace nearby { -namespace connections { - -namespace { - -OutputStream* GetOutputStreamOrNull(BluetoothSocket& socket) { - if (socket.GetRemoteDevice().IsValid()) return &socket.GetOutputStream(); - return nullptr; -} - -InputStream* GetInputStreamOrNull(BluetoothSocket& socket) { - if (socket.GetRemoteDevice().IsValid()) return &socket.GetInputStream(); - return nullptr; -} - -} // namespace - -BluetoothEndpointChannel::BluetoothEndpointChannel( - const std::string& channel_name, BluetoothSocket socket) - : BaseEndpointChannel(channel_name, GetInputStreamOrNull(socket), - GetOutputStreamOrNull(socket)), - bluetooth_socket_(std::move(socket)) {} - -proto::connections::Medium BluetoothEndpointChannel::GetMedium() const { - return proto::connections::Medium::BLUETOOTH; -} - -void BluetoothEndpointChannel::CloseImpl() { - auto status = bluetooth_socket_.Close(); - if (!status.Ok()) { - NEARBY_LOG(INFO, "Failed to close BT socket: exception=%d", status.value); - } -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/bluetooth_endpoint_channel.h b/cpp/core_v2/internal/bluetooth_endpoint_channel.h deleted file mode 100644 index 64fc0cc0..00000000 --- a/cpp/core_v2/internal/bluetooth_endpoint_channel.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef CORE_V2_INTERNAL_BLUETOOTH_ENDPOINT_CHANNEL_H_ -#define CORE_V2_INTERNAL_BLUETOOTH_ENDPOINT_CHANNEL_H_ - -#include - -#include "core_v2/internal/base_endpoint_channel.h" -#include "platform_v2/public/bluetooth_classic.h" -#include "proto/connections_enums.pb.h" - -namespace location { -namespace nearby { -namespace connections { - -class BluetoothEndpointChannel final : public BaseEndpointChannel { - public: - // Creates both outgoing and incoming BT channels. - BluetoothEndpointChannel(const std::string& channel_name, - BluetoothSocket bluetooth_socket); - - proto::connections::Medium GetMedium() const override; - - private: - void CloseImpl() override; - - BluetoothSocket bluetooth_socket_; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_BLUETOOTH_ENDPOINT_CHANNEL_H_ diff --git a/cpp/core_v2/internal/client_proxy.cc b/cpp/core_v2/internal/client_proxy.cc deleted file mode 100644 index e4e5f24c..00000000 --- a/cpp/core_v2/internal/client_proxy.cc +++ /dev/null @@ -1,525 +0,0 @@ -#include "core_v2/internal/client_proxy.h" - -#include -#include -#include - -#include "platform_v2/base/base64_utils.h" -#include "platform_v2/base/prng.h" -#include "platform_v2/public/crypto.h" -#include "platform_v2/public/logging.h" -#include "platform_v2/public/mutex_lock.h" -#include "proto/connections_enums.pb.h" -#include "absl/container/flat_hash_map.h" -#include "absl/container/flat_hash_set.h" -#include "absl/strings/escaping.h" -#include "absl/strings/str_cat.h" - -namespace location { -namespace nearby { -namespace connections { - -ClientProxy::ClientProxy() : client_id_(Prng().NextInt64()) {} - -ClientProxy::~ClientProxy() { Reset(); } - -std::int64_t ClientProxy::GetClientId() const { return client_id_; } - -std::string ClientProxy::GetLocalEndpointId() { - if (local_endpoint_id_.empty()) { - // 1) Concatenate the Random 64-bit value with "client" string. - // 2) Compute a hash of that concatenation. - // 3) Base64-encode that hash, to make it human-readable. - // 4) Use only the first kEndpointIdLength bytes to make ID. - ByteArray id_hash = - Crypto::Sha256(absl::StrCat("client", prng_.NextInt64())); - std::string id = Base64Utils::Encode(id_hash).substr(0, kEndpointIdLength); - NEARBY_LOG( - INFO, - "ClientProxy [Local Endpoint Generated]: client=%p; endpoint_id=%s", - this, id.c_str()); - local_endpoint_id_ = id; - } - return local_endpoint_id_; -} - -void ClientProxy::Reset() { - MutexLock lock(&mutex_); - - StoppedAdvertising(); - StoppedDiscovery(); - RemoveAllEndpoints(); -} - -void ClientProxy::StartedAdvertising( - const std::string& service_id, Strategy strategy, - const ConnectionListener& listener, - absl::Span mediums) { - MutexLock lock(&mutex_); - - if (connections_.empty()) local_endpoint_id_.clear(); - advertising_info_ = {service_id, listener}; -} - -void ClientProxy::StoppedAdvertising() { - MutexLock lock(&mutex_); - - if (IsAdvertising()) { - advertising_info_.Clear(); - } - if (connections_.empty()) local_endpoint_id_.clear(); -} - -bool ClientProxy::IsAdvertising() const { - MutexLock lock(&mutex_); - - return !advertising_info_.IsEmpty(); -} - -std::string ClientProxy::GetAdvertisingServiceId() const { - MutexLock lock(&mutex_); - return advertising_info_.service_id; -} - -std::string ClientProxy::GetServiceId() const { - MutexLock lock(&mutex_); - if (IsAdvertising()) - return advertising_info_.service_id; - if (IsDiscovering()) - return discovery_info_.service_id; - return "idle_service_id"; -} - -void ClientProxy::StartedDiscovery( - const std::string& service_id, Strategy strategy, - const DiscoveryListener& listener, - absl::Span mediums) { - MutexLock lock(&mutex_); - - if (connections_.empty()) local_endpoint_id_.clear(); - discovery_info_ = DiscoveryInfo{service_id, listener}; -} - -void ClientProxy::StoppedDiscovery() { - MutexLock lock(&mutex_); - - if (IsDiscovering()) { - discovered_endpoint_ids_.clear(); - discovery_info_.Clear(); - } - if (connections_.empty()) local_endpoint_id_.clear(); -} - -bool ClientProxy::IsDiscoveringServiceId(const std::string& service_id) const { - MutexLock lock(&mutex_); - - return IsDiscovering() && service_id == discovery_info_.service_id; -} - -bool ClientProxy::IsDiscovering() const { - MutexLock lock(&mutex_); - - return !discovery_info_.IsEmpty(); -} - -std::string ClientProxy::GetDiscoveryServiceId() const { - MutexLock lock(&mutex_); - - return discovery_info_.service_id; -} - -void ClientProxy::OnEndpointFound(const std::string& service_id, - const std::string& endpoint_id, - const ByteArray& endpoint_info, - proto::connections::Medium medium) { - MutexLock lock(&mutex_); - - NEARBY_LOG(INFO, - "ClientProxy [Endpoint Found]: [enter] id=%s; service=%s; info=%s", - endpoint_id.c_str(), service_id.c_str(), - absl::BytesToHexString(endpoint_info.data()).c_str()); - if (!IsDiscoveringServiceId(service_id)) { - NEARBY_LOG(INFO, "ClientProxy [Endpoint Found]: [no discovery] id=%s", - endpoint_id.c_str()); - return; - } - if (discovered_endpoint_ids_.count(endpoint_id)) { - NEARBY_LOG(INFO, "ClientProxy [Endpoint Found]: [duplicate] id=%s", - endpoint_id.c_str()); - return; - } - discovered_endpoint_ids_.insert(endpoint_id); - discovery_info_.listener.endpoint_found_cb(endpoint_id, endpoint_info, - service_id); -} - -void ClientProxy::OnEndpointLost(const std::string& service_id, - const std::string& endpoint_id) { - MutexLock lock(&mutex_); - - if (!IsDiscoveringServiceId(service_id)) return; - const auto it = discovered_endpoint_ids_.find(endpoint_id); - if (it == discovered_endpoint_ids_.end()) return; - discovered_endpoint_ids_.erase(it); - discovery_info_.listener.endpoint_lost_cb(endpoint_id); -} - -void ClientProxy::OnConnectionInitiated(const std::string& endpoint_id, - const ConnectionResponseInfo& info, - const ConnectionOptions& options, - const ConnectionListener& listener) { - MutexLock lock(&mutex_); - - // Whether this is incoming or outgoing, the local and remote endpoints both - // still need to accept this connection, so set its establishment status to - // PENDING. - auto result = connections_.emplace( - endpoint_id, Connection{ - .is_incoming = info.is_incoming_connection, - .connection_listener = listener, - .connection_options = options, - }); - // Instead of using structured binding which is nice, but banned - // (can not use c++17 features, until chromium does) we unpack manually. - auto& pair_iter = result.first; - bool inserted = result.second; - NEARBY_LOG(INFO, - "ClientProxy [Connection Initiated]: add Connection: client=%p, " - "id=%s; inserted=%d", - this, endpoint_id.c_str(), inserted); - DCHECK(inserted); - const Connection& item = pair_iter->second; - // Notify the client. - // - // Note: we allow devices to connect to an advertiser even after it stops - // advertising, so no need to check IsAdvertising() here. - item.connection_listener.initiated_cb(endpoint_id, info); -} - -void ClientProxy::OnConnectionAccepted(const std::string& endpoint_id) { - MutexLock lock(&mutex_); - - if (!HasPendingConnectionToEndpoint(endpoint_id)) { - NEARBY_LOG( - INFO, "ClientProxy [Connection Accepted]: no pending connection; id=%s", - endpoint_id.c_str()); - return; - } - - // Notify the client. - Connection* item = LookupConnection(endpoint_id); - if (item != nullptr) { - item->connection_listener.accepted_cb(endpoint_id); - item->status = Connection::kConnected; - } -} - -void ClientProxy::OnConnectionRejected(const std::string& endpoint_id, - const Status& status) { - MutexLock lock(&mutex_); - - if (!HasPendingConnectionToEndpoint(endpoint_id)) { - NEARBY_LOG( - INFO, "ClientProxy [Connection Rejected]: no pending connection; id=%s", - endpoint_id.c_str()); - return; - } - - // Notify the client. - const Connection* item = LookupConnection(endpoint_id); - if (item != nullptr) { - item->connection_listener.rejected_cb(endpoint_id, status); - OnDisconnected(endpoint_id, false /* notify */); - } -} - -void ClientProxy::OnBandwidthChanged(const std::string& endpoint_id, - Medium new_medium) { - MutexLock lock(&mutex_); - - const Connection* item = LookupConnection(endpoint_id); - if (item != nullptr) { - item->connection_listener.bandwidth_changed_cb(endpoint_id, new_medium); - } -} - -void ClientProxy::OnDisconnected(const std::string& endpoint_id, bool notify) { - MutexLock lock(&mutex_); - - const Connection* item = LookupConnection(endpoint_id); - if (item != nullptr) { - if (notify) { - item->connection_listener.disconnected_cb({endpoint_id}); - } - connections_.erase(endpoint_id); - if (connections_.empty()) local_endpoint_id_.clear(); - } -} - -bool ClientProxy::ConnectionStatusMatches(const std::string& endpoint_id, - Connection::Status status) const { - MutexLock lock(&mutex_); - - const Connection* item = LookupConnection(endpoint_id); - if (item != nullptr) { - return item->status == status; - } - return false; -} - -BooleanMediumSelector ClientProxy::GetUpgradeMediums( - const std::string& endpoint_id) const { - MutexLock lock(&mutex_); - - const Connection* item = LookupConnection(endpoint_id); - if (item != nullptr) { - return item->connection_options.allowed; - } - return {}; -} - -bool ClientProxy::IsConnectedToEndpoint(const std::string& endpoint_id) const { - return ConnectionStatusMatches(endpoint_id, Connection::kConnected); -} - -std::vector ClientProxy::GetMatchingEndpoints( - std::function pred) const { - MutexLock lock(&mutex_); - - std::vector connected_endpoints; - - for (const auto& pair : connections_) { - const auto& endpoint_id = pair.first; - const auto& connection = pair.second; - if (pred(connection)) { - connected_endpoints.push_back(endpoint_id); - } - } - return connected_endpoints; -} - -std::vector ClientProxy::GetPendingConnectedEndpoints() const { - return GetMatchingEndpoints([](const Connection& connection) { - return connection.status != Connection::kConnected; - }); -} - -std::vector ClientProxy::GetConnectedEndpoints() const { - return GetMatchingEndpoints([](const Connection& connection) { - return connection.status == Connection::kConnected; - }); -} - -std::int32_t ClientProxy::GetNumOutgoingConnections() const { - return GetMatchingEndpoints([](const Connection& connection) { - return connection.status == Connection::kConnected && - !connection.is_incoming; - }) - .size(); -} - -std::int32_t ClientProxy::GetNumIncomingConnections() const { - return GetMatchingEndpoints([](const Connection& connection) { - return connection.status == Connection::kConnected && - connection.is_incoming; - }) - .size(); -} - -bool ClientProxy::HasPendingConnectionToEndpoint( - const std::string& endpoint_id) const { - MutexLock lock(&mutex_); - - const Connection* item = LookupConnection(endpoint_id); - if (item != nullptr) { - return item->status != Connection::kConnected; - } - return false; -} - -bool ClientProxy::HasLocalEndpointResponded( - const std::string& endpoint_id) const { - MutexLock lock(&mutex_); - - return ConnectionStatusesContains( - endpoint_id, - static_cast(Connection::kLocalEndpointAccepted | - Connection::kLocalEndpointRejected)); -} - -bool ClientProxy::HasRemoteEndpointResponded( - const std::string& endpoint_id) const { - MutexLock lock(&mutex_); - - return ConnectionStatusesContains( - endpoint_id, - static_cast(Connection::kRemoteEndpointAccepted | - Connection::kRemoteEndpointRejected)); -} - -void ClientProxy::LocalEndpointAcceptedConnection( - const std::string& endpoint_id, const PayloadListener& listener) { - MutexLock lock(&mutex_); - - if (HasLocalEndpointResponded(endpoint_id)) { - NEARBY_LOG( - INFO, - "ClientProxy [Local Accepted]: local endpoint has responded; id=%s", - endpoint_id.c_str()); - return; - } - - AppendConnectionStatus(endpoint_id, Connection::kLocalEndpointAccepted); - Connection* item = LookupConnection(endpoint_id); - if (item != nullptr) { - item->payload_listener = listener; - } -} - -void ClientProxy::LocalEndpointRejectedConnection( - const std::string& endpoint_id) { - MutexLock lock(&mutex_); - - if (HasLocalEndpointResponded(endpoint_id)) { - NEARBY_LOG( - INFO, - "ClientProxy [Local Rejected]: local endpoint has responded; id=%s", - endpoint_id.c_str()); - return; - } - - AppendConnectionStatus(endpoint_id, Connection::kLocalEndpointRejected); -} - -void ClientProxy::RemoteEndpointAcceptedConnection( - const std::string& endpoint_id) { - MutexLock lock(&mutex_); - - if (HasRemoteEndpointResponded(endpoint_id)) { - NEARBY_LOG( - INFO, - "ClientProxy [Remote Accepted]: remote endpoint has responded; id=%s", - endpoint_id.c_str()); - return; - } - - AppendConnectionStatus(endpoint_id, Connection::kRemoteEndpointAccepted); -} - -void ClientProxy::RemoteEndpointRejectedConnection( - const std::string& endpoint_id) { - MutexLock lock(&mutex_); - - if (HasRemoteEndpointResponded(endpoint_id)) { - NEARBY_LOG( - INFO, - "ClientProxy [Remote Rejected]: remote endpoint has responded; id=%s", - endpoint_id.c_str()); - return; - } - - AppendConnectionStatus(endpoint_id, Connection::kRemoteEndpointRejected); -} - -bool ClientProxy::IsConnectionAccepted(const std::string& endpoint_id) const { - MutexLock lock(&mutex_); - - return ConnectionStatusesContains(endpoint_id, - Connection::kLocalEndpointAccepted) && - ConnectionStatusesContains(endpoint_id, - Connection::kRemoteEndpointAccepted); -} - -bool ClientProxy::IsConnectionRejected(const std::string& endpoint_id) const { - MutexLock lock(&mutex_); - - return ConnectionStatusesContains( - endpoint_id, - static_cast(Connection::kLocalEndpointRejected | - Connection::kRemoteEndpointRejected)); -} - -bool ClientProxy::LocalConnectionIsAccepted(std::string endpoint_id) const { - return ConnectionStatusesContains( - endpoint_id, ClientProxy::Connection::kLocalEndpointAccepted); -} - -bool ClientProxy::RemoteConnectionIsAccepted(std::string endpoint_id) const { - return ConnectionStatusesContains( - endpoint_id, ClientProxy::Connection::kRemoteEndpointAccepted); -} - -void ClientProxy::OnPayload(const std::string& endpoint_id, Payload payload) { - MutexLock lock(&mutex_); - - if (IsConnectedToEndpoint(endpoint_id)) { - const Connection* item = LookupConnection(endpoint_id); - if (item != nullptr) { - item->payload_listener.payload_cb(endpoint_id, std::move(payload)); - } - } -} - -const ClientProxy::Connection* ClientProxy::LookupConnection( - const std::string& endpoint_id) const { - auto item = connections_.find(endpoint_id); - return item != connections_.end() ? &item->second : nullptr; -} - -ClientProxy::Connection* ClientProxy::LookupConnection( - const std::string& endpoint_id) { - auto item = connections_.find(endpoint_id); - return item != connections_.end() ? &item->second : nullptr; -} - -void ClientProxy::OnPayloadProgress(const std::string& endpoint_id, - const PayloadProgressInfo& info) { - MutexLock lock(&mutex_); - - if (IsConnectedToEndpoint(endpoint_id)) { - Connection* item = LookupConnection(endpoint_id); - if (item != nullptr) { - item->payload_listener.payload_progress_cb(endpoint_id, info); - } - } -} - -bool operator==(const ClientProxy& lhs, const ClientProxy& rhs) { - return lhs.GetClientId() == rhs.GetClientId(); -} - -bool operator<(const ClientProxy& lhs, const ClientProxy& rhs) { - return lhs.GetClientId() < rhs.GetClientId(); -} - -void ClientProxy::RemoveAllEndpoints() { - MutexLock lock(&mutex_); - - // Note: we may want to notify the client of onDisconnected() for each - // endpoint, in the case when this is called from stopAllEndpoints(). For now, - // just remove without notifying. - connections_.clear(); - local_endpoint_id_.clear(); -} - -bool ClientProxy::ConnectionStatusesContains( - const std::string& endpoint_id, Connection::Status status_to_match) const { - const Connection* item = LookupConnection(endpoint_id); - if (item != nullptr) { - return (item->status & status_to_match) != 0; - } - return false; -} - -void ClientProxy::AppendConnectionStatus(const std::string& endpoint_id, - Connection::Status status_to_append) { - Connection* item = LookupConnection(endpoint_id); - if (item != nullptr) { - item->status = - static_cast(item->status | status_to_append); - } -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/client_proxy.h b/cpp/core_v2/internal/client_proxy.h deleted file mode 100644 index d2e88d3f..00000000 --- a/cpp/core_v2/internal/client_proxy.h +++ /dev/null @@ -1,228 +0,0 @@ -#ifndef CORE_V2_INTERNAL_CLIENT_PROXY_H_ -#define CORE_V2_INTERNAL_CLIENT_PROXY_H_ - -#include -#include -#include - -#include "core_v2/listeners.h" -#include "core_v2/options.h" -#include "core_v2/status.h" -#include "core_v2/strategy.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/prng.h" -#include "platform_v2/public/mutex.h" -#include "proto/connections_enums.pb.h" -// Prefer using absl:: versions of a set and a map; they tend to be more -// efficient: implementation is using open-addressing hash tables. -#include "absl/container/flat_hash_map.h" -#include "absl/container/flat_hash_set.h" -#include "absl/types/span.h" - -namespace location { -namespace nearby { -namespace connections { - -// CLientProxy is tracking state of client's connection, and serves as -// a proxy for notifications sent to this client. -class ClientProxy final { - public: - static constexpr int kEndpointIdLength = 4; - - ClientProxy(); - ~ClientProxy(); - ClientProxy(ClientProxy&&) = default; - ClientProxy& operator=(ClientProxy&&) = default; - - std::int64_t GetClientId() const; - - std::string GetLocalEndpointId(); - - // Clears all the runtime state of this client. - void Reset(); - - // Marks this client as advertising with the given callbacks. - void StartedAdvertising( - const std::string& service_id, Strategy strategy, - const ConnectionListener& connection_lifecycle_listener, - absl::Span mediums); - // Marks this client as not advertising. - void StoppedAdvertising(); - bool IsAdvertising() const; - std::string GetAdvertisingServiceId() const; - - // Get service ID of a surrently active link (either advertising, or - // discovering). - std::string GetServiceId() const; - - // Marks this client as discovering with the given callback. - void StartedDiscovery(const std::string& service_id, Strategy strategy, - const DiscoveryListener& discovery_listener, - absl::Span mediums); - // Marks this client as not discovering at all. - void StoppedDiscovery(); - bool IsDiscoveringServiceId(const std::string& service_id) const; - bool IsDiscovering() const; - std::string GetDiscoveryServiceId() const; - - // Proxies to the client's DiscoveryListener::OnEndpointFound() callback. - void OnEndpointFound(const std::string& service_id, - const std::string& endpoint_id, - const ByteArray& endpoint_info, - proto::connections::Medium medium); - // Proxies to the client's DiscoveryListener::OnEndpointLost() callback. - void OnEndpointLost(const std::string& service_id, - const std::string& endpoint_id); - - // Proxies to the client's ConnectionListener::OnInitiated() callback. - void OnConnectionInitiated(const std::string& endpoint_id, - const ConnectionResponseInfo& info, - const ConnectionOptions& options, - const ConnectionListener& listener); - - // Proxies to the client's ConnectionListener::OnAccepted() callback. - void OnConnectionAccepted(const std::string& endpoint_id); - // Proxies to the client's ConnectionListener::OnRejected() callback. - void OnConnectionRejected(const std::string& endpoint_id, - const Status& status); - - void OnBandwidthChanged(const std::string& endpoint_id, Medium new_medium); - - // Removes the endpoint from this client's list of connected endpoints. If - // notify is true, also calls the client's - // ConnectionListener.disconnected_cb() callback. - void OnDisconnected(const std::string& endpoint_id, bool notify); - - // Returns all mediums eligible for upgrade. - BooleanMediumSelector GetUpgradeMediums(const std::string& endpoint_id) const; - // Returns true if it's safe to send payloads to this endpoint. - bool IsConnectedToEndpoint(const std::string& endpoint_id) const; - // Returns all endpoints that can safely be sent payloads. - std::vector GetConnectedEndpoints() const; - // Returns all endpoints that are still awaiting acceptance. - std::vector GetPendingConnectedEndpoints() const; - // Returns the number of endpoints that are connected and outgoing. - std::int32_t GetNumOutgoingConnections() const; - // Returns the number of endpoints that are connected and incoming. - std::int32_t GetNumIncomingConnections() const; - // If true, then we're in the process of approving (or rejecting) a - // connection. No payloads should be sent until isConnectedToEndpoint() - // returns true. - bool HasPendingConnectionToEndpoint(const std::string& endpoint_id) const; - // Returns true if the local endpoint has already marked itself as - // accepted/rejected. - bool HasLocalEndpointResponded(const std::string& endpoint_id) const; - // Returns true if the remote endpoint has already marked themselves as - // accepted/rejected. - bool HasRemoteEndpointResponded(const std::string& endpoint_id) const; - // Marks the local endpoint as having accepted the connection. - void LocalEndpointAcceptedConnection(const std::string& endpoint_id, - const PayloadListener& listener); - // Marks the local endpoint as having rejected the connection. - void LocalEndpointRejectedConnection(const std::string& endpoint_id); - // Marks the remote endpoint as having accepted the connection. - void RemoteEndpointAcceptedConnection(const std::string& endpoint_id); - // Marks the remote endpoint as having rejected the connection. - void RemoteEndpointRejectedConnection(const std::string& endpoint_id); - // Returns true if both the local endpoint and the remote endpoint have - // accepted the connection. - bool IsConnectionAccepted(const std::string& endpoint_id) const; - // Returns true if either the local endpoint or the remote endpoint has - // rejected the connection. - bool IsConnectionRejected(const std::string& endpoint_id) const; - - // Proxies to the client's PayloadListener::OnPayload() callback. - void OnPayload(const std::string& endpoint_id, Payload payload); - // Proxies to the client's PayloadListener::OnPayloadProgress() callback. - void OnPayloadProgress(const std::string& endpoint_id, - const PayloadProgressInfo& info); - bool LocalConnectionIsAccepted(std::string endpoint_id) const; - bool RemoteConnectionIsAccepted(std::string endpoint_id) const; - - private: - struct Connection { - // Status: may be either: - // Connection::PENDING, or combination of - // Connection::LOCAL_ENDPOINT_ACCEPTED: - // Connection::LOCAL_ENDPOINT_REJECTED and - // Connection::REMOTE_ENDPOINT_ACCEPTED: - // Connection::REMOTE_ENDPOINT_REJECTED, or - // Connection::CONNECTED. - // Only when this is set to CONNECTED should you allow payload transfers. - // - // We want this enum to be implicitly convertible to int, because - // we perform bit operations on it. - enum Status : uint8_t { - kPending = 0, - kLocalEndpointAccepted = 1 << 0, - kLocalEndpointRejected = 1 << 1, - kRemoteEndpointAccepted = 1 << 2, - kRemoteEndpointRejected = 1 << 3, - kConnected = 1 << 4, - }; - bool is_incoming{false}; - Status status{kPending}; - ConnectionListener connection_listener; - PayloadListener payload_listener; - ConnectionOptions connection_options; - }; - - struct AdvertisingInfo { - std::string service_id; - ConnectionListener listener; - void Clear() { service_id.clear(); } - bool IsEmpty() const { return service_id.empty(); } - }; - - struct DiscoveryInfo { - std::string service_id; - DiscoveryListener listener; - void Clear() { service_id.clear(); } - bool IsEmpty() const { return service_id.empty(); } - }; - - void RemoveAllEndpoints(); - bool ConnectionStatusesContains(const std::string& endpoint_id, - Connection::Status status_to_match) const; - void AppendConnectionStatus(const std::string& endpoint_id, - Connection::Status status_to_append); - - const Connection* LookupConnection(const std::string& endpoint_id) const; - Connection* LookupConnection(const std::string& endpoint_id); - bool ConnectionStatusMatches(const std::string& endpoint_id, - Connection::Status status) const; - std::vector GetMatchingEndpoints( - std::function pred) const; - - mutable RecursiveMutex mutex_; - std::int64_t client_id_; - std::string local_endpoint_id_; - Prng prng_; - - // If not empty, we are currently advertising and accepting connection - // requests for the given service_id. - AdvertisingInfo advertising_info_; - - // If not empty, we are currently discovering for the given service_id. - DiscoveryInfo discovery_info_; - - // Maps endpoint_id to endpoint connection state. - absl::flat_hash_map connections_; - - // A cache of endpoint ids that we've already notified the discoverer of. We - // check this cache before calling onEndpointFound() so that we don't notify - // the client multiple times for the same endpoint. This would otherwise - // happen because some mediums (like Bluetooth) repeatedly give us the same - // endpoints after each scan. - absl::flat_hash_set discovered_endpoint_ids_; -}; - -// Operator overloads when comparing Ptr. -bool operator==(const ClientProxy& lhs, const ClientProxy& rhs); -bool operator<(const ClientProxy& lhs, const ClientProxy& rhs); - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_CLIENT_PROXY_H_ diff --git a/cpp/core_v2/internal/encryption_runner.cc b/cpp/core_v2/internal/encryption_runner.cc deleted file mode 100644 index ddddd887..00000000 --- a/cpp/core_v2/internal/encryption_runner.cc +++ /dev/null @@ -1,368 +0,0 @@ -#include "core_v2/internal/encryption_runner.h" - -#include -#include -#include - -#include "platform_v2/base/base64_utils.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/exception.h" -#include "platform_v2/public/cancelable_alarm.h" -#include "platform_v2/public/logging.h" -#include "securegcm/ukey2_handshake.h" -#include "absl/strings/ascii.h" -#include "absl/time/clock.h" -#include "absl/time/time.h" - -namespace location { -namespace nearby { -namespace connections { -namespace { - -constexpr absl::Duration kTimeout = absl::Seconds(15); -constexpr std::int32_t kMaxUkey2VerificationStringLength = 32; -constexpr std::int32_t kTokenLength = 5; -constexpr securegcm::UKey2Handshake::HandshakeCipher kCipher = - securegcm::UKey2Handshake::HandshakeCipher::P256_SHA512; - -// Transforms a raw UKEY2 token (which is a random ByteArray that's -// kMaxUkey2VerificationStringLength long) into a kTokenLength string that only -// uses [A-Z], [0-9], '_', '-' for each character. -std::string ToHumanReadableString(const ByteArray& token) { - std::string result = Base64Utils::Encode(token).substr(0, kTokenLength); - absl::AsciiStrToUpper(&result); - return result; -} - -bool HandleEncryptionSuccess(const std::string& endpoint_id, - std::unique_ptr ukey2, - const EncryptionRunner::ResultListener& listener) { - std::unique_ptr verification_string = - ukey2->GetVerificationString(kMaxUkey2VerificationStringLength); - if (verification_string == nullptr) { - return false; - } - - ByteArray raw_authentication_token(*verification_string); - - listener.on_success_cb(endpoint_id, std::move(ukey2), - ToHumanReadableString(raw_authentication_token), - raw_authentication_token); - - return true; -} - -void CancelableAlarmRunnable(ClientProxy* client, - const std::string& endpoint_id, - EndpointChannel* endpoint_channel) { - NEARBY_LOG(INFO, - "Timing out encryption for client %" PRId64 - " to endpoint %s after %" PRId64 " ms", - client->GetClientId(), endpoint_id.c_str(), - static_cast(absl::ToInt64Milliseconds(kTimeout))); - endpoint_channel->Close(); -} - -class ServerRunnable final { - public: - ServerRunnable(ClientProxy* client, ScheduledExecutor* alarm_executor, - const std::string& endpoint_id, EndpointChannel* channel, - EncryptionRunner::ResultListener&& listener) - : client_(client), - alarm_executor_(alarm_executor), - endpoint_id_(endpoint_id), - channel_(channel), - listener_(std::move(listener)) {} - - void operator()() const { - CancelableAlarm timeout_alarm( - "EncryptionRunner.StartServer() timeout", - [this]() { CancelableAlarmRunnable(client_, endpoint_id_, channel_); }, - kTimeout, alarm_executor_); - - std::unique_ptr server = - securegcm::UKey2Handshake::ForResponder(kCipher); - if (server == nullptr) { - LogException(); - HandleHandshakeOrIoException(&timeout_alarm); - return; - } - - // Message 1 (Client Init) - ExceptionOr client_init = channel_->Read(); - if (!client_init.ok()) { - LogException(); - HandleHandshakeOrIoException(&timeout_alarm); - return; - } - - securegcm::UKey2Handshake::ParseResult parse_result = - server->ParseHandshakeMessage(std::string(client_init.result())); - - // Java code throws a HandshakeException / AlertException. - if (!parse_result.success) { - LogException(); - if (parse_result.alert_to_send != nullptr) { - HandleAlertException(parse_result); - } - HandleHandshakeOrIoException(&timeout_alarm); - return; - } - - NEARBY_LOG(INFO, "In StartServer(), read UKEY2 Message 1 from endpoint %s", - endpoint_id_.c_str()); - - // Message 2 (Server Init) - std::unique_ptr server_init = - server->GetNextHandshakeMessage(); - - // Java code throws a HandshakeException. - if (server_init == nullptr) { - LogException(); - HandleHandshakeOrIoException(&timeout_alarm); - return; - } - - Exception write_exception = - channel_->Write(ByteArray(std::move(*server_init))); - if (!write_exception.Ok()) { - LogException(); - HandleHandshakeOrIoException(&timeout_alarm); - return; - } - - NEARBY_LOG(INFO, "In StartServer(), wrote UKEY2 Message 2 to endpoint %s", - endpoint_id_.c_str()); - - // Message 3 (Client Finish) - ExceptionOr client_finish = channel_->Read(); - - if (!client_finish.ok()) { - LogException(); - HandleHandshakeOrIoException(&timeout_alarm); - return; - } - - parse_result = - server->ParseHandshakeMessage(std::string(client_finish.result())); - - // Java code throws an AlertException or a HandshakeException. - if (!parse_result.success) { - LogException(); - if (parse_result.alert_to_send != nullptr) { - HandleAlertException(parse_result); - } - HandleHandshakeOrIoException(&timeout_alarm); - return; - } - - NEARBY_LOG(INFO, "In StartServer(), read UKEY2 Message 3 from endpoint %s", - endpoint_id_.c_str()); - - timeout_alarm.Cancel(); - - if (!HandleEncryptionSuccess(endpoint_id_, std::move(server), listener_)) { - LogException(); - HandleHandshakeOrIoException(&timeout_alarm); - return; - } - } - - private: - void LogException() const { - NEARBY_LOG(ERROR, "In StartServer(), UKEY2 failed with endpoint %s", - endpoint_id_.c_str()); - } - - void HandleHandshakeOrIoException(CancelableAlarm* timeout_alarm) const { - timeout_alarm->Cancel(); - listener_.on_failure_cb(endpoint_id_, channel_); - } - - void HandleAlertException( - const securegcm::UKey2Handshake::ParseResult& parse_result) const { - Exception write_exception = - channel_->Write(ByteArray(*parse_result.alert_to_send)); - if (!write_exception.Ok()) { - NEARBY_LOG(WARNING, - "In StartServer(), client %" PRId64 - " failed to pass the alert error message to endpoint %s", - client_->GetClientId(), endpoint_id_.c_str()); - } - } - - ClientProxy* client_; - ScheduledExecutor* alarm_executor_; - const std::string endpoint_id_; - EndpointChannel* channel_; - EncryptionRunner::ResultListener listener_; -}; - -class ClientRunnable final { - public: - ClientRunnable(ClientProxy* client, ScheduledExecutor* alarm_executor, - const std::string& endpoint_id, EndpointChannel* channel, - EncryptionRunner::ResultListener&& listener) - : client_(client), - alarm_executor_(alarm_executor), - endpoint_id_(endpoint_id), - channel_(channel), - listener_(std::move(listener)) {} - - void operator()() const { - CancelableAlarm timeout_alarm( - "EncryptionRunner.startClient() timeout", - [this]() { CancelableAlarmRunnable(client_, endpoint_id_, channel_); }, - kTimeout, alarm_executor_); - - std::unique_ptr crypto = - securegcm::UKey2Handshake::ForInitiator(kCipher); - - // Java code throws a HandshakeException. - if (crypto == nullptr) { - LogException(); - HandleHandshakeOrIoException(&timeout_alarm); - return; - } - - // Message 1 (Client Init) - std::unique_ptr client_init = - crypto->GetNextHandshakeMessage(); - - // Java code throws a HandshakeException. - if (client_init == nullptr) { - LogException(); - HandleHandshakeOrIoException(&timeout_alarm); - return; - } - - Exception write_init_exception = channel_->Write(ByteArray(*client_init)); - if (!write_init_exception.Ok()) { - LogException(); - HandleHandshakeOrIoException(&timeout_alarm); - return; - } - - NEARBY_LOG(INFO, "In startClient(), wrote UKEY2 Message 1 to endpoint %s", - endpoint_id_.c_str()); - - // Message 2 (Server Init) - ExceptionOr server_init = channel_->Read(); - - if (!server_init.ok()) { - LogException(); - HandleHandshakeOrIoException(&timeout_alarm); - return; - } - - securegcm::UKey2Handshake::ParseResult parse_result = - crypto->ParseHandshakeMessage(std::string(server_init.result())); - - // Java code throws an AlertException or a HandshakeException. - if (!parse_result.success) { - LogException(); - if (parse_result.alert_to_send != nullptr) { - HandleAlertException(parse_result); - } - HandleHandshakeOrIoException(&timeout_alarm); - return; - } - - NEARBY_LOG(INFO, "In startClient(), read UKEY2 Message 2 from endpoint %s", - endpoint_id_.c_str()); - - // Message 3 (Client Finish) - std::unique_ptr client_finish = - crypto->GetNextHandshakeMessage(); - - // Java code throws a HandshakeException. - if (client_finish == nullptr) { - LogException(); - HandleHandshakeOrIoException(&timeout_alarm); - return; - } - - Exception write_finish_exception = - channel_->Write(ByteArray(*client_finish)); - if (!write_finish_exception.Ok()) { - LogException(); - HandleHandshakeOrIoException(&timeout_alarm); - return; - } - - NEARBY_LOG(INFO, "In startClient(), wrote UKEY2 Message 3 to endpoint %s", - endpoint_id_.c_str()); - - timeout_alarm.Cancel(); - - if (!HandleEncryptionSuccess(endpoint_id_, std::move(crypto), listener_)) { - LogException(); - HandleHandshakeOrIoException(&timeout_alarm); - return; - } - } - - private: - void LogException() const { - NEARBY_LOG(ERROR, "In startClient(), UKEY2 failed with endpoint %s", - endpoint_id_.c_str()); - } - - void HandleHandshakeOrIoException(CancelableAlarm* timeout_alarm) const { - timeout_alarm->Cancel(); - listener_.on_failure_cb(endpoint_id_, channel_); - } - - void HandleAlertException( - const securegcm::UKey2Handshake::ParseResult& parse_result) const { - Exception write_exception = - channel_->Write(ByteArray(*parse_result.alert_to_send)); - if (!write_exception.Ok()) { - NEARBY_LOG(WARNING, - "In startClient(), client %" PRId64 - " failed to pass the alert error message to endpoint %s", - client_->GetClientId(), endpoint_id_.c_str()); - } - } - - ClientProxy* client_; - ScheduledExecutor* alarm_executor_; - const std::string endpoint_id_; - EndpointChannel* channel_; - EncryptionRunner::ResultListener listener_; -}; - -} // namespace - -EncryptionRunner::~EncryptionRunner() { - // Stop all the ongoing Runnables (as gracefully as possible). - client_executor_.Shutdown(); - server_executor_.Shutdown(); - alarm_executor_.Shutdown(); -} - -void EncryptionRunner::StartServer( - ClientProxy* client, const std::string& endpoint_id, - EndpointChannel* endpoint_channel, - EncryptionRunner::ResultListener&& listener) { - server_executor_.Execute( - [runnable{ServerRunnable(client, &alarm_executor_, endpoint_id, - endpoint_channel, std::move(listener))}]() { - runnable(); - }); -} - -void EncryptionRunner::StartClient( - ClientProxy* client, const std::string& endpoint_id, - EndpointChannel* endpoint_channel, - EncryptionRunner::ResultListener&& listener) { - client_executor_.Execute( - [runnable{ClientRunnable(client, &alarm_executor_, endpoint_id, - endpoint_channel, std::move(listener))}]() { - runnable(); - }); -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/encryption_runner.h b/cpp/core_v2/internal/encryption_runner.h deleted file mode 100644 index a3cd73ea..00000000 --- a/cpp/core_v2/internal/encryption_runner.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef CORE_V2_INTERNAL_ENCRYPTION_RUNNER_H_ -#define CORE_V2_INTERNAL_ENCRYPTION_RUNNER_H_ - -#include - -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/endpoint_channel.h" -#include "core_v2/listeners.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/public/scheduled_executor.h" -#include "platform_v2/public/single_thread_executor.h" -#include "securegcm/ukey2_handshake.h" - -namespace location { -namespace nearby { -namespace connections { - -// Encrypts a connection over UKEY2. -// -// NOTE: Stalled EndpointChannels will be disconnected after kTimeout. -// This is to prevent unverified endpoints from maintaining an -// indefinite connection to us. -class EncryptionRunner { - public: - EncryptionRunner() = default; - ~EncryptionRunner(); - - struct ResultListener { - // @EncryptionRunnerThread - std::function ukey2, - const std::string& auth_token, - const ByteArray& raw_auth_token)> - on_success_cb = - DefaultCallback, - const std::string&, const ByteArray&>(); - - // Encryption has failed. The remote_endpoint_id and channel are given so - // that any pending state can be cleaned up. - // - // We return the EndpointChannel because, at this stage, simultaneous - // connections are a possibility. Use this channel to verify that the state - // you're cleaning up is for this EndpointChannel, and not state for another - // channel to the same endpoint. - // - // @EncryptionRunnerThread - std::function - on_failure_cb = DefaultCallback(); - }; - - // @AnyThread - void StartServer(ClientProxy* client, const std::string& endpoint_id, - EndpointChannel* endpoint_channel, - ResultListener&& result_listener); - // @AnyThread - void StartClient(ClientProxy* client, const std::string& endpoint_id, - EndpointChannel* endpoint_channel, - ResultListener&& result_listener); - - private: - ScheduledExecutor alarm_executor_; - SingleThreadExecutor server_executor_; - SingleThreadExecutor client_executor_; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_ENCRYPTION_RUNNER_H_ diff --git a/cpp/core_v2/internal/endpoint_channel.h b/cpp/core_v2/internal/endpoint_channel.h deleted file mode 100644 index 7cd6877d..00000000 --- a/cpp/core_v2/internal/endpoint_channel.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef CORE_V2_INTERNAL_ENDPOINT_CHANNEL_H_ -#define CORE_V2_INTERNAL_ENDPOINT_CHANNEL_H_ - -#include -#include - -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/exception.h" -#include "platform_v2/public/mutex.h" -#include "proto/connections_enums.pb.h" -#include "securegcm/d2d_connection_context_v1.h" -#include "absl/time/clock.h" - -namespace location { -namespace nearby { -namespace connections { - -class EndpointChannel { - public: - virtual ~EndpointChannel() = default; - - using EncryptionContext = ::securegcm::D2DConnectionContextV1; - - virtual ExceptionOr - Read() = 0; // throws Exception::IO, Exception::INTERRUPTED - - virtual Exception Write(const ByteArray& data) = 0; // throws Exception::IO - - // Closes this EndpointChannel, without tracking the closure in analytics. - virtual void Close() = 0; - - // Closes this EndpointChannel and records the closure with the given reason. - virtual void Close(proto::connections::DisconnectionReason reason) = 0; - - // Returns a one-word type descriptor for the concrete EndpointChannel - // implementation that can be used in log messages; eg: BLUETOOTH, BLE, WIFI. - virtual std::string GetType() const = 0; - - // Returns the name of the EndpointChannel. - virtual std::string GetName() const = 0; - - // Returns the analytics enum representing the medium of this EndpointChannel. - virtual proto::connections::Medium GetMedium() const = 0; - - // Enables encryption on the EndpointChannel. - virtual void EnableEncryption(std::shared_ptr context) = 0; - - // True if the EndpointChannel is currently pausing all writes. - virtual bool IsPaused() const = 0; - - // Pauses all writes on this EndpointChannel until resume() is called. - virtual void Pause() = 0; - - // Resumes any writes on this EndpointChannel that were suspended when pause() - // was called. - virtual void Resume() = 0; - - // Returns the timestamp of the last read from this endpoint, or -1 if no - // reads have occurred. - virtual absl::Time GetLastReadTimestamp() const = 0; -}; - -inline bool operator==(const EndpointChannel& lhs, const EndpointChannel& rhs) { - return (lhs.GetType() == rhs.GetType()) && (lhs.GetName() == rhs.GetName()) && - (lhs.GetMedium() == rhs.GetMedium()); -} - -inline bool operator!=(const EndpointChannel& lhs, const EndpointChannel& rhs) { - return !(lhs == rhs); -} - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_ENDPOINT_CHANNEL_H_ diff --git a/cpp/core_v2/internal/endpoint_channel_manager.cc b/cpp/core_v2/internal/endpoint_channel_manager.cc deleted file mode 100644 index d3d0354c..00000000 --- a/cpp/core_v2/internal/endpoint_channel_manager.cc +++ /dev/null @@ -1,142 +0,0 @@ -#include "core_v2/internal/endpoint_channel_manager.h" - -#include - -#include "platform_v2/public/logging.h" -#include "platform_v2/public/mutex.h" -#include "platform_v2/public/mutex_lock.h" - -namespace location { -namespace nearby { -namespace connections { - -EndpointChannelManager::~EndpointChannelManager() { - MutexLock lock(&mutex_); - channel_state_.DestroyAll(); -} - -void EndpointChannelManager::RegisterChannelForEndpoint( - ClientProxy* client, const std::string& endpoint_id, - std::unique_ptr channel) { - MutexLock lock(&mutex_); - - SetActiveEndpointChannel(client, endpoint_id, std::move(channel)); - - NEARBY_LOG(INFO, "Registered channel: id=%s", endpoint_id.c_str()); -} - -void EndpointChannelManager::ReplaceChannelForEndpoint( - ClientProxy* client, const std::string& endpoint_id, - std::unique_ptr channel) { - MutexLock lock(&mutex_); - - auto* endpoint = channel_state_.LookupEndpointData(endpoint_id); - if (endpoint != nullptr && endpoint->channel == nullptr) { - NEARBY_LOG(INFO, "Channel is missing while trying to update: id=%s", - endpoint_id.c_str()); - } - - SetActiveEndpointChannel(client, endpoint_id, std::move(channel)); -} - -bool EndpointChannelManager::EncryptChannelForEndpoint( - const std::string& endpoint_id, - std::unique_ptr context) { - MutexLock lock(&mutex_); - - channel_state_.UpdateEncryptionContextForEndpoint(endpoint_id, - std::move(context)); - auto* endpoint = channel_state_.LookupEndpointData(endpoint_id); - return channel_state_.EncryptChannel(endpoint); -} - -std::shared_ptr EndpointChannelManager::GetChannelForEndpoint( - const std::string& endpoint_id) { - MutexLock lock(&mutex_); - - auto* endpoint = channel_state_.LookupEndpointData(endpoint_id); - if (endpoint == nullptr) { - NEARBY_LOG(INFO, "No channel info: id=%s", endpoint_id.c_str()); - return {}; - } - - return endpoint->channel; -} - -void EndpointChannelManager::SetActiveEndpointChannel( - ClientProxy* client, const std::string& endpoint_id, - std::unique_ptr channel) { - // Update the channel first, then encrypt this new channel, if - // crypto context is present. - channel_state_.UpdateChannelForEndpoint(endpoint_id, std::move(channel)); - - auto* endpoint = channel_state_.LookupEndpointData(endpoint_id); - if (endpoint->IsEncrypted()) channel_state_.EncryptChannel(endpoint); -} - -int EndpointChannelManager::GetConnectedEndpointsCount() const { - MutexLock lock(&mutex_); - return channel_state_.GetConnectedEndpointsCount(); -} - -///////////////////////////////// ChannelState ///////////////////////////////// - -// endpoint - channel endpoint to encrypt -bool EndpointChannelManager::ChannelState::EncryptChannel( - EndpointChannelManager::ChannelState::EndpointData* endpoint) { - if (endpoint != nullptr && endpoint->channel != nullptr && - endpoint->context != nullptr) { - endpoint->channel->EnableEncryption(endpoint->context); - return true; - } - return false; -} - -EndpointChannelManager::ChannelState::EndpointData* -EndpointChannelManager::ChannelState::LookupEndpointData( - const std::string& endpoint_id) { - auto item = endpoints_.find(endpoint_id); - return item != endpoints_.end() ? &item->second : nullptr; -} - -void EndpointChannelManager::ChannelState::UpdateChannelForEndpoint( - const std::string& endpoint_id, std::unique_ptr channel) { - // Create EndpointData instance, if necessary, and populate channel. - endpoints_[endpoint_id].channel = std::move(channel); -} - -void EndpointChannelManager::ChannelState::UpdateEncryptionContextForEndpoint( - const std::string& endpoint_id, - std::unique_ptr context) { - // Create EndpointData instance, if necessary, and populate crypto context. - endpoints_[endpoint_id].context = std::move(context); -} - -bool EndpointChannelManager::ChannelState::RemoveEndpoint( - const std::string& endpoint_id, - proto::connections::DisconnectionReason reason) { - auto item = endpoints_.find(endpoint_id); - if (item == endpoints_.end()) return false; - item->second.disconnect_reason = reason; - endpoints_.erase(item); - return true; -} - -bool EndpointChannelManager::UnregisterChannelForEndpoint( - const std::string& endpoint_id) { - MutexLock lock(&mutex_); - - if (!channel_state_.RemoveEndpoint( - endpoint_id, - proto::connections::DisconnectionReason::LOCAL_DISCONNECTION)) { - return false; - } - - NEARBY_LOG(INFO, "Unregistered channel: id=%s", endpoint_id.c_str()); - - return true; -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/endpoint_channel_manager.h b/cpp/core_v2/internal/endpoint_channel_manager.h deleted file mode 100644 index b9f82dc3..00000000 --- a/cpp/core_v2/internal/endpoint_channel_manager.h +++ /dev/null @@ -1,158 +0,0 @@ -#ifndef CORE_V2_INTERNAL_ENDPOINT_CHANNEL_MANAGER_H_ -#define CORE_V2_INTERNAL_ENDPOINT_CHANNEL_MANAGER_H_ - -#include -#include - -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/endpoint_channel.h" -#include "platform_v2/public/logging.h" -#include "platform_v2/public/mutex.h" -#include "securegcm/d2d_connection_context_v1.h" -#include "absl/container/flat_hash_map.h" - -namespace location { -namespace nearby { -namespace connections { - -// NOTE(std::string): -// All the strings in internal class public interfaces should be exchanged as -// const std::string& if they are immutable, and as std::string -// it they are mutable. -// This is to keep all the internal classes compatible with each other, -// and minimize resources spent on the type conversion. -// Project-wide, strings are either passed around as reference (which has -// zero maintenance costs, and sizeof(void*) memory usage => passed around in a -// CPU register), and whenever lifetime etension is required, it must be copied -// to std::string instance (which will again propagate as a const reference -// within it's lifetime domain). - -// Manages the communication channels to all the remote endpoints with which we -// are interacting. -class EndpointChannelManager final { - public: - using EncryptionContext = EndpointChannel::EncryptionContext; - - ~EndpointChannelManager(); - - // Registers the initial EndpointChannel to be associated with an endpoint; - // if there already exists a previously-associated EndpointChannel, that will - // be closed before continuing the registration. - void RegisterChannelForEndpoint(ClientProxy* client, - const std::string& endpoint_id, - std::unique_ptr channel) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Replaces the EndpointChannel to be associated with an endpoint from here on - // in, transferring the encryption context from the previous EndpointChannel - // to the newly-provided EndpointChannel. - void ReplaceChannelForEndpoint(ClientProxy* client, - const std::string& endpoint_id, - std::unique_ptr channel) - ABSL_LOCKS_EXCLUDED(mutex_); - - bool EncryptChannelForEndpoint(const std::string& endpoint_id, - std::unique_ptr context) - ABSL_LOCKS_EXCLUDED(mutex_); - - // NOTE(shared_ptr<> usage): - // - // EndpointChannelManager is holding an EndpointChannel instance; - // GetChannelForEndpoint() is passing ownership over to a worker thread. - // It is not a pointer passing but an ownership passing, to guarantee that - // channel instance will not disappear underneath the feet of a worker thread - // inside EndpointManager [ EndpointManager::EndpointChannelLoopRunnable() ]. - // If it is just a pointer, Channel will get destroyed while in use by a - // worker thread. shared_ptr is a simple and reliable tool to avoid that. - // - // The reason why it can not be std::unique_ptr<> is: there are other code - // paths that expect to be able to read the pointer value multiple times, from - // multiple places (each of them needs "ownership" for the duration of their - // use). EndpointManager::SendTransferFrameBytes() is another such place. - // If EndpointChannelManager replaces the current channel, and any (or both) - // EndpointManager methods that use a channel are running, it is better to - // have a shared ownership. - std::shared_ptr GetChannelForEndpoint( - const std::string& endpoint_id) ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns true if 'endpoint_id' actually had a registered EndpointChannel. - // IOW, a return of false signifies a no-op. - bool UnregisterChannelForEndpoint(const std::string& endpoint_id) - ABSL_LOCKS_EXCLUDED(mutex_); - - int GetConnectedEndpointsCount() const ABSL_LOCKS_EXCLUDED(mutex_); - - private: - // Tracks channel state for all endpoints. This includes what EndpointChannel - // the endpoint is currently using and whether or not the EndpointChannel has - // been encrypted yet. - class ChannelState { - public: - struct EndpointData { - EndpointData() = default; - EndpointData(EndpointData&&) = default; - EndpointData& operator=(EndpointData&&) = default; - ~EndpointData() { - if (channel != nullptr) { - channel->Close(disconnect_reason); - } - } - - // True if we have a 'context' for the endpoint. - bool IsEncrypted() const { return context != nullptr; } - - std::shared_ptr channel; - std::shared_ptr context; - proto::connections::DisconnectionReason disconnect_reason = - proto::connections::DisconnectionReason::UNKNOWN_DISCONNECTION_REASON; - }; - - ChannelState() = default; - ~ChannelState() { DestroyAll(); } - ChannelState(ChannelState&&) = default; - ChannelState& operator=(ChannelState&&) = default; - - // Provides a way to destroy contents of a container, while holding a lock. - void DestroyAll() { endpoints_.clear(); } - // Return pointer to endpoint data, or nullptr, it not found. - EndpointData* LookupEndpointData(const std::string& endpoint_id); - - // Stores a new EndpointChannel for the endpoint. - // Prevoius one is destroyed, if it existed. - void UpdateChannelForEndpoint(const std::string& endpoint_id, - std::unique_ptr channel); - - // Stores a new EncryptionContext for the endpoint. - // Prevoius one is destroyed, if it existed. - void UpdateEncryptionContextForEndpoint( - const std::string& endpoint_id, - std::unique_ptr context); - - // Removes all knowledge of this endpoint, cleaning up as necessary. - // Returns false if the endpoint was not found. - bool RemoveEndpoint(const std::string& endpoint_id, - proto::connections::DisconnectionReason reason); - - bool EncryptChannel(EndpointData* endpoint); - int GetConnectedEndpointsCount() const { return endpoints_.size(); } - - private: - // Endpoint ID -> EndpointData. Contains everything we know about the - // endpoint. - absl::flat_hash_map endpoints_; - }; - - void SetActiveEndpointChannel(ClientProxy* client, - const std::string& endpoint_id, - std::unique_ptr channel) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - mutable Mutex mutex_; - ChannelState channel_state_ ABSL_GUARDED_BY(mutex_); -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_ENDPOINT_CHANNEL_MANAGER_H_ diff --git a/cpp/core_v2/internal/endpoint_manager.cc b/cpp/core_v2/internal/endpoint_manager.cc deleted file mode 100644 index 04bf5890..00000000 --- a/cpp/core_v2/internal/endpoint_manager.cc +++ /dev/null @@ -1,544 +0,0 @@ -#include "core_v2/internal/endpoint_manager.h" - -#include -#include - -#include "core_v2/internal/endpoint_channel.h" -#include "core_v2/internal/offline_frames.h" -#include "platform_v2/base/exception.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/logging.h" -#include "proto/connections_enums.pb.h" - -namespace location { -namespace nearby { -namespace connections { - -using ::location::nearby::proto::connections::Medium; - -constexpr absl::Duration EndpointManager::kKeepAliveWriteInterval; -constexpr absl::Duration EndpointManager::kKeepAliveReadTimeout; -constexpr absl::Duration EndpointManager::kProcessEndpointDisconnectionTimeout; -constexpr absl::Time EndpointManager::kInvalidTimestamp; - -// A Runnable that continuously grabs the most recent EndpointChannel available -// for an endpoint. -// -// handler - Called whenever an EndpointChannel is available for endpointId. -// Implementations are expected to read/write freely to the -// EndpointChannel until an Exception::IO is thrown. Once an -// Exception::IO occurs, a check will be performed to see if another -// EndpointChannel is available for the given endpoint and, if so, -// handler(EndpointChannel) will be called again. Return false to exit -// the loop. -void EndpointManager::EndpointChannelLoopRunnable( - const std::string& runnable_name, ClientProxy* client, - const std::string& endpoint_id, CountDownLatch* barrier, - std::function(EndpointChannel*)> handler) { - // EndpointChannelManager will not let multiple channels exist simultaneously - // for the same endpoint_id; it will be closing "old" channels as new ones - // come. (There will be a short overlap). - // Closed channel will return Exception::kIo for any Read, and loop (below) - // will retry and attempt to pick another channel. - // If channel is deleted (no mapping), or it is still the same channel - // (same Medium) on which we got the Exception::kIo, we terminate the loop. - Medium last_failed_medium = Medium::UNKNOWN_MEDIUM; - while (true) { - // It's important to keep re-fetching the EndpointChannel for an endpoint - // because it can be changed out from under us (for example, when we - // upgrade from Bluetooth to Wifi). - std::shared_ptr channel = - channel_manager_->GetChannelForEndpoint(endpoint_id); - if (channel == nullptr) { - NEARBY_LOG(INFO, "Endpoint channel is nullptr, bail out."); - break; - } - - // If we're looping back around after a failure, and there's not a new - // EndpointChannel for this endpoint, there's nothing more to do here. - if ((last_failed_medium != Medium::UNKNOWN_MEDIUM) && - (channel->GetMedium() == last_failed_medium)) { - NEARBY_LOG( - INFO, "No new endpoint channel is found after a failure, exit loop."); - break; - } - - ExceptionOr keep_using_channel = handler(channel.get()); - - if (!keep_using_channel.ok()) { - Exception exception = keep_using_channel.GetException(); - if (exception.Raised(Exception::kIo)) { - last_failed_medium = channel->GetMedium(); - NEARBY_LOG(INFO, "Endpoint channel IO exception; last_failed_medium=%d", - last_failed_medium); - continue; - } - if (exception.Raised(Exception::kInterrupted)) { - break; - } - } - - if (!keep_using_channel.result()) { - NEARBY_LOG(INFO, "Dropping current channel: last medium=%d", - last_failed_medium); - break; - } - } - // Indicate we're out of the loop and it is ok to schedule another instance - // if needed. - NEARBY_LOG(INFO, "Worker going down; name=%s; id=%s", runnable_name.c_str(), - endpoint_id.c_str()); - barrier->CountDown(); - - // Always clear out all state related to this endpoint before terminating - // this thread. - DiscardEndpoint(client, endpoint_id); - NEARBY_LOG(INFO, "Worker done; name=%s; id=%s", runnable_name.c_str(), - endpoint_id.c_str()); -} - -ExceptionOr EndpointManager::HandleData( - const std::string& endpoint_id, ClientProxy* client, - EndpointChannel* endpoint_channel) { - // Read as much as we can from the healthy EndpointChannel - when it is no - // longer in good shape (i.e. our read from it throws an Exception), our - // super class will loop back around and try our luck in case there's been - // a replacement for this endpoint since we last checked with the - // EndpointChannelManager. - while (true) { - ExceptionOr bytes = endpoint_channel->Read(); - if (!bytes.ok()) { - NEARBY_LOG(INFO, "Stop reading on read-time exception: %d", - bytes.exception()); - return ExceptionOr(bytes.exception()); - } - ExceptionOr wrapped_frame = parser::FromBytes(bytes.result()); - if (!wrapped_frame.ok()) { - if (wrapped_frame.GetException().Raised( - Exception::kInvalidProtocolBuffer)) { - NEARBY_LOG(INFO, "Failed to decode; endpoint=%s; channel=%s; skip", - endpoint_id.c_str(), endpoint_channel->GetType().c_str()); - continue; - } else { - NEARBY_LOG(INFO, "Stop reading on parse-time exception: %d", - wrapped_frame.exception()); - return ExceptionOr(wrapped_frame.exception()); - } - } - OfflineFrame& frame = wrapped_frame.result(); - - // Route the incoming offlineFrame to its registered processor. - V1Frame::FrameType frame_type = parser::GetFrameType(frame); - EndpointManager::FrameProcessor* frame_processor = - GetFrameProcessor(frame_type); - if (frame_processor == nullptr) { - // report messages without handlers, except KEEP_ALIVE, which has - // no explicit handler. - if (frame_type == V1Frame::KEEP_ALIVE) { - NEARBY_LOG(INFO, "KeepAlive message for: id=%s", endpoint_id.c_str()); - } else if (frame_type == V1Frame::DISCONNECTION) { - NEARBY_LOG(INFO, "Disconnect message for: id=%s", endpoint_id.c_str()); - endpoint_channel->Close(); - } else { - NEARBY_LOG(ERROR, "Unhandled message: id=%s, type=%d", - endpoint_id.c_str(), frame_type); - } - continue; - } - - frame_processor->OnIncomingFrame(frame, endpoint_id, client, - endpoint_channel->GetMedium()); - } -} - -ExceptionOr EndpointManager::HandleKeepAlive( - EndpointChannel* endpoint_channel) { - // Check if it has been too long since we received a frame from our - // endpoint. - auto last_read_time = endpoint_channel->GetLastReadTimestamp(); - if (last_read_time != kInvalidTimestamp && - SystemClock::ElapsedRealtime() > - (last_read_time + EndpointManager::kKeepAliveReadTimeout)) { - NEARBY_LOG(INFO, "Receive timeout expired; aborting KeepAlive worker."); - return ExceptionOr(false); - } - - // Attempt to send the KeepAlive frame over the endpoint channel - if the - // write fails, our super class will loop back around and try our luck again - // in case there's been a replacement for this endpoint. - Exception write_exception = endpoint_channel->Write(parser::ForKeepAlive()); - if (!write_exception.Ok()) { - return ExceptionOr(write_exception); - } - - // We sleep as the very last step because we want to minimize the caching of - // the EndpointChannel. If we do hold on to the EndpointChannel, and it's - // switched out from under us in BandwidthUpgradeManager, our write will - // trigger an erroneous write to the encryption context that will cascade - // into all our remote endpoint's future reads failing. - Exception sleep_exception = - SystemClock::Sleep(EndpointManager::kKeepAliveWriteInterval); - if (!sleep_exception.Ok()) { - return ExceptionOr(sleep_exception); - } - - return ExceptionOr(true); -} - -bool operator==(const EndpointManager::FrameProcessor& lhs, - const EndpointManager::FrameProcessor& rhs) { - // We're comparing addresses because these objects are callbacks which need to - // be matched by exact instances. - return &lhs == &rhs; -} - -bool operator<(const EndpointManager::FrameProcessor& lhs, - const EndpointManager::FrameProcessor& rhs) { - // We're comparing addresses because these objects are callbacks which need to - // be matched by exact instances. - return &lhs < &rhs; -} - -EndpointManager::EndpointManager(EndpointChannelManager* manager) - : channel_manager_(manager) {} - -EndpointManager::~EndpointManager() { - NEARBY_LOG(INFO, "EndpointManager going down"); - CountDownLatch latch(1); - RunOnEndpointManagerThread([this, &latch]() { - NEARBY_LOG(INFO, "Bringing down endpoints"); - for (auto& item : endpoints_) { - const std::string& endpoint_id = item.first; - EndpointState& state = item.second; - // This will close the channel; all workers will sense that and - // terminate. - channel_manager_->UnregisterChannelForEndpoint(endpoint_id); - state.barrier.Await(); - } - latch.CountDown(); - }); - latch.Await(); - NEARBY_LOG(INFO, "Bringing down worker threads"); - - // Stop all the ongoing Runnables (as gracefully as possible). - // Order matters: bring worker pools down first; serial_executor_ thread - // should go last, since workers schedule jobs there even during shutdown. - handlers_executor_.Shutdown(); - keep_alive_executor_.Shutdown(); - NEARBY_LOG(INFO, "Bringing down control thread"); - serial_executor_.Shutdown(); - NEARBY_LOG(INFO, "EndpointManager is down"); -} - -EndpointManager::FrameProcessor::Handle EndpointManager::RegisterFrameProcessor( - V1Frame::FrameType frame_type, EndpointManager::FrameProcessor* processor) { - const FrameProcessor::Handle handle = processor; - CountDownLatch latch(1); - RunOnEndpointManagerThread([this, frame_type, &latch, processor]() { - auto it = frame_processors_.find(frame_type); - if (it != frame_processors_.end()) { - NEARBY_LOGS(INFO) << "Frame processor found: updated; type=" << frame_type - << "; processor=" << processor << "; self=" << this; - it->second = processor; - } else { - NEARBY_LOGS(INFO) << "Frame processor added; type=" << frame_type - << "; processor=" << processor << "; self=" << this; - frame_processors_.emplace(frame_type, processor); - } - latch.CountDown(); - }); - latch.Await(); - return handle; -} - -void EndpointManager::UnregisterFrameProcessor(V1Frame::FrameType frame_type, - const void* handle, bool sync) { - NEARBY_LOGS(INFO) << "UnregisterFrameProcessor [enter]: handle=" << handle; - if (handle == nullptr) return; - CountDownLatch latch(1); - RunOnEndpointManagerThread([this, frame_type, handle, &latch, sync]() { - auto it = frame_processors_.find(frame_type); - if (it == frame_processors_.end()) { - NEARBY_LOGS(INFO) << "UnregisterFrameProcessor [not found]: handle=" - << handle; - if (sync) latch.CountDown(); - return; - } - NEARBY_LOGS(INFO) << "UnregisterFrameProcessor [found]: handle=" << handle; - if (it->second == handle) { - frame_processors_.erase(it); - NEARBY_LOGS(INFO) << "Unregistered: type=" << frame_type - << "; processor=" << handle << "; self=" << this; - } else { - NEARBY_LOG(INFO, - "Failed to unregister: type=%d; handle mismatch: passed=%p, " - "expected=%p", - frame_type, handle, it->second); - } - if (sync) latch.CountDown(); - }); - if (sync) { - latch.Await(); - NEARBY_LOGS(INFO) << "Unregistered [sync done]: type=" << frame_type - << "; processor=" << handle << "; self=" << this; - } -} - -EndpointManager::FrameProcessor* EndpointManager::GetFrameProcessor( - V1Frame::FrameType frame_type) { - EndpointManager::FrameProcessor* processor = nullptr; - CountDownLatch latch(1); - RunOnEndpointManagerThread([this, frame_type, &processor, &latch]() { - auto it = frame_processors_.find(frame_type); - if (it != frame_processors_.end()) { - processor = it->second; - } - latch.CountDown(); - }); - latch.Await(); - NEARBY_LOG(INFO, "GetFrameProcessor: type=%d; processor=%p", frame_type, - processor); - return processor; -} - -void EndpointManager::EnsureWorkersTerminated(const std::string& endpoint_id) { - auto item = endpoints_.find(endpoint_id); - if (item != endpoints_.end()) { - // If another instance of data and keep-alive handlers is running, it will - // terminate soon; we should block until it happens. - EndpointState& endpoint_state = item->second; - NEARBY_LOGS(INFO) << "Waiting for workers to terminate for id: " - << endpoint_id; - endpoint_state.barrier.Await(); - endpoints_.erase(item); - NEARBY_LOGS(INFO) << "Workers terminated for id: " << endpoint_id; - } else { - NEARBY_LOGS(INFO) << "EndpointState not found for id: " << endpoint_id; - } -} - -void EndpointManager::RegisterEndpoint(ClientProxy* client, - const std::string& endpoint_id, - const ConnectionResponseInfo& info, - const ConnectionOptions& options, - std::unique_ptr channel, - const ConnectionListener& listener) { - CountDownLatch latch(1); - - // NOTE (unique_ptr<> capture): - // std::unique_ptr<> is not copyable, so we can not pass it to - // lambda capture, because lambda eventually is converted to std::function<>. - // Instead, we release() a pointer, and pass a raw pointer, which is copyalbe. - // We ignore the risk of job not scheduled (and an associated risk of memory - // leak), because this may only happen during service shutdown. - RunOnEndpointManagerThread([this, client, channel = channel.release(), - &endpoint_id, &info, &options, &listener, - &latch]() { - // Pass ownership of channel to EndpointChannelManager - NEARBY_LOG(INFO, "Registering endpoint with channel manager: id=%s", - endpoint_id.c_str()); - channel_manager_->RegisterChannelForEndpoint( - client, endpoint_id, std::unique_ptr(channel)); - - EnsureWorkersTerminated(endpoint_id); - EndpointState& endpoint_state = - endpoints_.emplace(endpoint_id, EndpointState()).first->second; - endpoint_state.client = client; - - NEARBY_LOG(INFO, "Starting workers: id=%s", endpoint_id.c_str()); - // For every endpoint, there's normally only one Read handler instance - // running on the handlers_executor_ pool. This instance reads data from the - // endpoint and delegates incoming frames to various FrameProcessors. - // Once the frame has been properly handled, it starts reading again for - // the next frame. If the handler fails its read and no other - // EndpointChannels are available for this endpoint, a disconnection - // will be initiated. - StartEndpointReader( - [this, client, endpoint_id, barrier = &endpoint_state.barrier]() { - EndpointChannelLoopRunnable( - "Read", client, endpoint_id, barrier, - [this, client, endpoint_id](EndpointChannel* channel) { - return HandleData(endpoint_id, client, channel); - }); - }); - - // For every endpoint, there's only one KeepAliveManager instance - // running on the keep_alive_executor_ pool. This instance will - // periodically send out a ping* to the endpoint while listening for an - // incoming pong**. If it fails to send the ping, or if no pong is heard - // within kKeepAliveReadTimeoutMillis milliseconds, it initiates a - // disconnection. - // - // (*) Bluetooth requires a constant outgoing stream of messages. If - // there's silence, Android will break the socket. This is why we ping. - // (**) Wifi Hotspots can fail to notice a connection has been lost, and - // they will happily keep writing to /dev/null. This is why we listen - // for the pong. - StartEndpointKeepAliveManager([this, client, endpoint_id, - barrier = &endpoint_state.barrier]() { - EndpointChannelLoopRunnable("KeepAliveManager", client, endpoint_id, - barrier, [this](EndpointChannel* channel) { - return HandleKeepAlive(channel); - }); - }); - NEARBY_LOG(INFO, "Workers started, notifying client; id=%s", - endpoint_id.c_str()); - - // It's now time to let the client know of this new connection so that - // they can accept or reject it. - client->OnConnectionInitiated(endpoint_id, info, options, listener); - latch.CountDown(); - }); - latch.Await(); -} - -void EndpointManager::UnregisterEndpoint(ClientProxy* client, - const std::string& endpoint_id) { - CountDownLatch latch(1); - RunOnEndpointManagerThread([this, client, endpoint_id, &latch]() { - RemoveEndpoint(client, endpoint_id, - client->IsConnectedToEndpoint(endpoint_id)); - latch.CountDown(); - }); - latch.Await(); -} - -// Designed to run asynchronously. It is called from IO thread pools, and -// jobs in these pools may be waited for from the EndpointManager thread. If we -// allow synchronous behavior here it will cause a live lock. -void EndpointManager::DiscardEndpoint(ClientProxy* client, - const std::string& endpoint_id) { - RunOnEndpointManagerThread([this, client, endpoint_id]() { - RemoveEndpoint(client, endpoint_id, - /*notify=*/ - client->IsConnectedToEndpoint(endpoint_id)); - }); -} - -std::vector EndpointManager::SendPayloadChunk( - const PayloadTransferFrame::PayloadHeader& payload_header, - const PayloadTransferFrame::PayloadChunk& payload_chunk, - const std::vector& endpoint_ids) { - ByteArray bytes = - parser::ForDataPayloadTransfer(payload_header, payload_chunk); - - return SendTransferFrameBytes(endpoint_ids, bytes, payload_header.id(), - /*offset=*/payload_chunk.offset(), - /*packet_type=*/"DATA"); -} - -std::vector EndpointManager::SendControlMessage( - const PayloadTransferFrame::PayloadHeader& header, - const PayloadTransferFrame::ControlMessage& control, - const std::vector& endpoint_ids) { - ByteArray bytes = parser::ForControlPayloadTransfer(header, control); - - return SendTransferFrameBytes(endpoint_ids, bytes, header.id(), - /*offset=*/control.offset(), - /*packet_type=*/"CONTROL"); -} - -// @EndpointManagerThread -void EndpointManager::RemoveEndpoint(ClientProxy* client, - const std::string& endpoint_id, - bool notify) { - // Unregistering from channel_manager_ will also serve to terminate - // the dedicated handler and KeepAlive threads we started when we registered - // this endpoint. - if (channel_manager_->UnregisterChannelForEndpoint(endpoint_id)) { - // Notify all frame processors of the disconnection immediately and wait - // for them to clean up state. Only once all processors are done cleaning - // up, we can remove the endpoint from ClientProxy after which there - // should be no further interactions with the endpoint. - // (See b/37352254 for history) - WaitForEndpointDisconnectionProcessing(client, endpoint_id); - - client->OnDisconnected(endpoint_id, notify); - NEARBY_LOG(INFO, "Removed endpoint; id=%s", endpoint_id.c_str()); - } -} - -// @EndpointManagerThread -void EndpointManager::WaitForEndpointDisconnectionProcessing( - ClientProxy* client, const std::string& endpoint_id) { - NEARBY_LOGS(INFO) << "Wait: client=" << client << "; id=" << endpoint_id; - auto total_size = frame_processors_.size(); - NEARBY_LOGS(INFO) << "Total frame processors: " << total_size; - if (!total_size) return; - CountDownLatch barrier(total_size); - - int valid = 0; - for (auto& item : frame_processors_) { - auto* processor = item.second; - NEARBY_LOGS(INFO) << "processor=" << processor << "; type=" << item.first; - if (processor) { - valid++; - processor->OnEndpointDisconnect(client, endpoint_id, &barrier); - } else { - barrier.CountDown(); - } - } - - if (!valid) { - NEARBY_LOGS(INFO) << "No valid frame processors."; - return; - } else { - NEARBY_LOGS(INFO) << "Valid frame processors: " << valid; - } - - NEARBY_LOGS(INFO) << "Waiting for " << valid - << " frame processors to disconnect from: " << endpoint_id; - if (!barrier.Await(kProcessEndpointDisconnectionTimeout).result()) { - NEARBY_LOGS(INFO) << "Failed to disconnect frame processors from: " - << endpoint_id; - } else { - NEARBY_LOGS(INFO) - << "Finished waiting for frame processors to disconnect from: " - << endpoint_id; - } -} - -std::vector EndpointManager::SendTransferFrameBytes( - const std::vector& endpoint_ids, const ByteArray& bytes, - std::int64_t payload_id, std::int64_t offset, - const std::string& packet_type) { - std::vector failed_endpoint_ids; - for (const std::string& endpoint_id : endpoint_ids) { - std::shared_ptr channel = - channel_manager_->GetChannelForEndpoint(endpoint_id); - - if (channel == nullptr) { - // We no longer know about this endpoint (it was either explicitly - // unregistered, or a read/write error made us unregister it internally). - NEARBY_LOG(INFO, "Channel not available; id=%s", endpoint_id.c_str()); - failed_endpoint_ids.push_back(endpoint_id); - continue; - } - - Exception write_exception = channel->Write(bytes); - if (!write_exception.Ok()) { - failed_endpoint_ids.push_back(endpoint_id); - NEARBY_LOG(INFO, "Failed to send packet; endpoint_id=%s", - endpoint_id.c_str()); - continue; - } - } - - return failed_endpoint_ids; -} - -void EndpointManager::StartEndpointReader(Runnable runnable) { - handlers_executor_.Execute(std::move(runnable)); -} - -void EndpointManager::StartEndpointKeepAliveManager(Runnable runnable) { - keep_alive_executor_.Execute(std::move(runnable)); -} - -void EndpointManager::RunOnEndpointManagerThread(Runnable runnable) { - serial_executor_.Execute(std::move(runnable)); -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/endpoint_manager.h b/cpp/core_v2/internal/endpoint_manager.h deleted file mode 100644 index 898a6e86..00000000 --- a/cpp/core_v2/internal/endpoint_manager.h +++ /dev/null @@ -1,225 +0,0 @@ -#ifndef CORE_V2_INTERNAL_ENDPOINT_MANAGER_H_ -#define CORE_V2_INTERNAL_ENDPOINT_MANAGER_H_ - -#include -#include - -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/endpoint_channel.h" -#include "core_v2/internal/endpoint_channel_manager.h" -#include "core_v2/listeners.h" -#include "proto/connections/offline_wire_formats.pb.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/runnable.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/multi_thread_executor.h" -#include "platform_v2/public/single_thread_executor.h" -#include "platform_v2/public/system_clock.h" -#include "proto/connections_enums.pb.h" -#include "absl/container/flat_hash_map.h" -#include "absl/container/flat_hash_set.h" -#include "absl/time/time.h" - -namespace location { -namespace nearby { -namespace connections { - -// Manages all operations related to the remote endpoints with which we are -// interacting. -// -// All processing of incoming and outgoing payloads is spread across this and -// the PayloadManager as described below. -// -// The sending of outgoing payloads originates in -// PayloadManager::SendPayload() before control is transferred over to -// EndpointManager::SendPayloadChunk(). This work happens on one of three -// dedicated writer threads belonging to the PayloadManager. The writer thread -// that is used depends on the Payload::Type. -// -// The EndpointManager has one dedicated reader thread for each registered -// endpoint, and the receiving of every incoming payload (and its subsequent -// chunks) originates on one of those threads before control is transferred over -// to PayloadManager::ProcessFrame() (still running on that -// same dedicated reader thread). - -class EndpointManager { - public: - class FrameProcessor { - public: - using Handle = void*; - - virtual ~FrameProcessor() = default; - - // @EndpointManagerReaderThread - // Called for every incoming frame of registered type. - // NOTE(OfflineFrame& frame): - // For large payload in data phase, resources may be saved if data is moved, - // rather than copied (if passing data by reference is not an option). - // To achieve that, OfflineFrame needs to be either mutabe lvalue reference, - // or rvalue reference. Rvalue references are discouraged by go/cstyle, - // and that leaves us with mutable lvalue reference. - virtual void OnIncomingFrame(OfflineFrame& offline_frame, - const std::string& from_endpoint_id, - ClientProxy* to_client, - proto::connections::Medium current_medium) = 0; - - // Implementations must call barrier.CountDown() once - // they're done. This parallelizes the disconnection event across all frame - // processors. - // - // @EndpointManagerThread - virtual void OnEndpointDisconnect(ClientProxy* client, - const std::string& endpoint_id, - CountDownLatch* barrier) = 0; - }; - - explicit EndpointManager(EndpointChannelManager* manager); - ~EndpointManager(); - - // Invoked from the constructors of the various *Manager components that make - // up the OfflineServiceController implementation. - // FrameProcessor* instances are of dynamic duration and survive all sessions. - // returns unique handle to be used for unregistering. - // Blocks until registration is complete. - FrameProcessor::Handle RegisterFrameProcessor(V1Frame::FrameType frame_type, - FrameProcessor* processor); - void UnregisterFrameProcessor(V1Frame::FrameType frame_type, - const void* handle, bool sync = false); - - // Invoked from the different PcpHandler implementations (of which there can - // be only one at a time). - // Blocks until registration is complete. - void RegisterEndpoint(ClientProxy* client, const std::string& endpoint_id, - const ConnectionResponseInfo& info, - const ConnectionOptions& options, - std::unique_ptr channel, - const ConnectionListener& listener); - // Called when a client explicitly asks to disconnect from this endpoint. In - // this case, we do not notify the client of onDisconnected(). - void UnregisterEndpoint(ClientProxy* client, const std::string& endpoint_id); - - // Returns the list of endpoints to which sending this chunk failed. - // - // Invoked from the PayloadManager's sendPayload() method. - std::vector SendPayloadChunk( - const PayloadTransferFrame::PayloadHeader& payload_header, - const PayloadTransferFrame::PayloadChunk& payload_chunk, - const std::vector& endpoint_ids); - std::vector SendControlMessage( - const PayloadTransferFrame::PayloadHeader& payload_header, - const PayloadTransferFrame::ControlMessage& control_message, - const std::vector& endpoint_ids); - - // Called when we internally want to get rid of the endpoint, without the - // client directly telling us to. For example... - // a) We failed to read from the endpoint in its dedicated reader thread. - // b) We failed to write to the endpoint in PayloadManager. - // c) The connection was rejected in PCPHandler. - // d) The dedicated KeepAlive thread exceeded its period of inactivity. - // Or in the numerous other cases where a failure occurred and we no longer - // believe the endpoint is in a healthy state. - // - // Note: This must not block. Otherwise we can get into a deadlock where we - // ask everyone who's registered an FrameProcessor to - // processEndpointDisconnection() while the caller of DiscardEndpoint() is - // blocked here. - void DiscardEndpoint(ClientProxy* client, const std::string& endpoint_id); - - private: - struct EndpointState { - // ClientProxy object associated with this endpoint. - ClientProxy* client; - // Execution barrier, used to ensure that all workers associated with an - // endpoint on handlers_executor_ and keep_alive_executor_ are terminated. - CountDownLatch barrier{2}; - }; - - FrameProcessor* GetFrameProcessor(V1Frame::FrameType frame_type); - - ExceptionOr HandleData(const std::string& endpoint_id, - ClientProxy* client_proxy, - EndpointChannel* endpoint_channel); - - ExceptionOr HandleKeepAlive(EndpointChannel* endpoint_channel); - - // Waits for a given endpoint EndpointChannelLoopRunnable() workers to - // terminate. - // Is called from RegisterEndpoint to avoid races; also called from - // RemoveEndpoint as part of proper endpoint shutdown sequence. - // @EndpointManagerThread - void EnsureWorkersTerminated(const std::string& endpoint_id); - - void EndpointChannelLoopRunnable( - const std::string& runnable_name, ClientProxy* client_proxy, - const std::string& endpoint_id, CountDownLatch* barrier, - std::function(EndpointChannel*)> handler); - - static void WaitForLatch(const std::string& method_name, - CountDownLatch* latch); - static void WaitForLatch(const std::string& method_name, - CountDownLatch* latch, std::int32_t timeout_millis); - - static constexpr absl::Duration kKeepAliveWriteInterval = - absl::Milliseconds(5000); - static constexpr absl::Duration kKeepAliveReadTimeout = - absl::Milliseconds(30000); - static constexpr absl::Duration kProcessEndpointDisconnectionTimeout = - absl::Milliseconds(2000); - static constexpr std::int32_t kMaxConcurrentEndpoints = 50; - static constexpr absl::Time kInvalidTimestamp = absl::InfinitePast(); - - // It should be noted that this method may be called multiple times (because - // invoking this method closes the endpoint channel, which causes the - // dedicated reader and KeepAlive threads to terminate, which in turn leads to - // this method being called), but that's alright because the implementation of - // this method is idempotent. - // @EndpointManagerThread - void RemoveEndpoint(ClientProxy* client, const std::string& endpoint_id, - bool notify); - - void WaitForEndpointDisconnectionProcessing(ClientProxy* client, - const std::string& endpoint_id); - - std::vector SendTransferFrameBytes( - const std::vector& endpoint_ids, - const ByteArray& payload_transfer_frame_bytes, std::int64_t payload_id, - std::int64_t offset, const std::string& packet_type); - - // Executes data-handing jobs on a separate thread for each endpoint, on a - // handlers_executor_. - // If amount of concurrent connections is less the pool capacity, it is - // possible that while a channel is being replaced, two jobs are trying to - // run for the same endpoint (for a short time). - // TODO (apolyudov): do not let extra job start. - void StartEndpointReader(Runnable runnable); - - // Executes keep-alive jobs on a separate thread for each endpoint on a - // keep_alive_executor_. - void StartEndpointKeepAliveManager(Runnable runnable); - - // Executes all jobs sequentially, on a serial_executor_. - void RunOnEndpointManagerThread(Runnable runnable); - - EndpointChannelManager* channel_manager_; - - absl::flat_hash_map frame_processors_; - - // We keep track of all registered channel endpoints here. - absl::flat_hash_map endpoints_; - - MultiThreadExecutor keep_alive_executor_{kMaxConcurrentEndpoints}; - MultiThreadExecutor handlers_executor_{kMaxConcurrentEndpoints}; - SingleThreadExecutor serial_executor_; -}; - -// Operator overloads when comparing FrameProcessor*. -bool operator==(const EndpointManager::FrameProcessor& lhs, - const EndpointManager::FrameProcessor& rhs); -bool operator<(const EndpointManager::FrameProcessor& lhs, - const EndpointManager::FrameProcessor& rhs); - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_ENDPOINT_MANAGER_H_ diff --git a/cpp/core_v2/internal/internal_payload.cc b/cpp/core_v2/internal/internal_payload.cc deleted file mode 100644 index 8e042093..00000000 --- a/cpp/core_v2/internal/internal_payload.cc +++ /dev/null @@ -1,18 +0,0 @@ -#include "core_v2/internal/internal_payload.h" - -namespace location { -namespace nearby { -namespace connections { - -InternalPayload::InternalPayload(Payload payload) - : payload_(std::move(payload)), payload_id_(payload_.GetId()) {} - -Payload InternalPayload::ReleasePayload() { - return std::move(payload_); -} - -Payload::Id InternalPayload::GetId() const { return payload_id_; } - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/internal_payload.h b/cpp/core_v2/internal/internal_payload.h deleted file mode 100644 index c2bdd868..00000000 --- a/cpp/core_v2/internal/internal_payload.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef CORE_V2_INTERNAL_INTERNAL_PAYLOAD_H_ -#define CORE_V2_INTERNAL_INTERNAL_PAYLOAD_H_ - -#include - -#include "core_v2/payload.h" -#include "proto/connections/offline_wire_formats.pb.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/exception.h" - -namespace location { -namespace nearby { -namespace connections { - -// Defines the operations layered atop a Payload, for use inside the -// OfflineServiceController. -// -//

There will be an extension of this abstract base class per type of -// Payload. -class InternalPayload { - public: - explicit InternalPayload(Payload payload); - virtual ~InternalPayload() = default; - - Payload ReleasePayload(); - - Payload::Id GetId() const; - - // Returns the PayloadType of the Payload to which this object is bound. - // - //

Note that this is supposed to return the type from the OfflineFrame - // proto rather than what is already available via - // Payload::getType(). - // - // @return The PayloadType. - virtual PayloadTransferFrame::PayloadHeader::PayloadType GetType() const = 0; - - // Deduces the total size of the Payload to which this object is bound. - // - // @return The total size, or -1 if it cannot be deduced (for example, when - // dealing with streaming data). - virtual std::int64_t GetTotalSize() const = 0; - - // Breaks off the next chunk from the Payload to which this object is bound. - // - //

Used when we have a complete Payload that we want to break into smaller - // byte blobs for sending across a hard boundary (like the other side of - // a Binder, or another device altogether). - // - // @return The next chunk from the Payload, or null if we've reached the end. - virtual ByteArray DetachNextChunk() = 0; - - // Adds the next chunk that comprises the Payload to which this object is - // bound. - // - //

Used when we are trying to reconstruct a Payload that lives on the - // other side of a hard boundary (like the other side of a Binder, or another - // device altogether), one byte blob at a time. - // - // @param chunk The next chunk; this being null signals that this is the last - // chunk, which will typically be used as a trigger to perform whatever state - // cleanup may be required by the concrete implementation. - virtual Exception AttachNextChunk(const ByteArray& chunk) = 0; - - // Cleans up any resources used by this Payload. Called when we're stopping - // early, e.g. after being cancelled or having no more recipients left. - virtual void Close() {} - - protected: - Payload payload_; - // We're caching the payload ID here because the backing payload will be - // released to another owner during the lifetime of an incoming - // InternalPayload. - Payload::Id payload_id_; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_INTERNAL_PAYLOAD_H_ diff --git a/cpp/core_v2/internal/internal_payload_factory.cc b/cpp/core_v2/internal/internal_payload_factory.cc deleted file mode 100644 index 41eb6cca..00000000 --- a/cpp/core_v2/internal/internal_payload_factory.cc +++ /dev/null @@ -1,279 +0,0 @@ -#include "core_v2/internal/internal_payload_factory.h" - -#include -#include - -#include "core_v2/payload.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/exception.h" -#include "platform_v2/public/condition_variable.h" -#include "platform_v2/public/file.h" -#include "platform_v2/public/mutex.h" -#include "platform_v2/public/pipe.h" -#include "absl/memory/memory.h" - -namespace location { -namespace nearby { -namespace connections { - -namespace { - -class BytesInternalPayload : public InternalPayload { - public: - explicit BytesInternalPayload(Payload payload) - : InternalPayload(std::move(payload)), - total_size_(payload_.AsBytes().size()), - detached_only_chunk_(false) {} - - PayloadTransferFrame::PayloadHeader::PayloadType GetType() const override { - return PayloadTransferFrame::PayloadHeader::BYTES; - } - - std::int64_t GetTotalSize() const override { return total_size_; } - - // Relinquishes ownership of the payload_; retrieves and returns the stored - // ByteArray. - ByteArray DetachNextChunk() override { - if (detached_only_chunk_) { - return {}; - } - - detached_only_chunk_ = true; - return std::move(payload_).AsBytes(); - } - - // Does nothing. - Exception AttachNextChunk(const ByteArray& chunk) override { - return {Exception::kSuccess}; - } - - private: - // We're caching the total size here because the backing payload will be - // moved to another owner during the lifetime of an incoming - // InternalPayload. - const std::int64_t total_size_; - bool detached_only_chunk_; -}; - -class OutgoingStreamInternalPayload : public InternalPayload { - public: - explicit OutgoingStreamInternalPayload(Payload payload) - : InternalPayload(std::move(payload)) {} - - PayloadTransferFrame::PayloadHeader::PayloadType GetType() const override { - return PayloadTransferFrame::PayloadHeader::STREAM; - } - - std::int64_t GetTotalSize() const override { return -1; } - - ByteArray DetachNextChunk() override { - InputStream* input_stream = payload_.AsStream(); - if (!input_stream) return {}; - - ExceptionOr bytes_read = input_stream->Read(kChunkSize); - if (!bytes_read.ok()) { - input_stream->Close(); - return {}; - } - - ByteArray scoped_bytes_read = std::move(bytes_read.result()); - - if (scoped_bytes_read.Empty()) { - // TODO(reznor): logger.atVerbose().log("No more data for outgoing payload - // %s, closing InputStream.", this); - - input_stream->Close(); - return {}; - } - - return scoped_bytes_read; - } - - Exception AttachNextChunk(const ByteArray& chunk) override { - return {Exception::kIo}; - } - - void Close() override { - // Ignore the potential Exception returned by close(), as a counterpart - // to Java's closeQuietly(). - InputStream* stream = payload_.AsStream(); - if (stream) stream->Close(); - } - - private: - static constexpr std::int64_t kChunkSize = Pipe::kChunkSize; -}; - -class IncomingStreamInternalPayload : public InternalPayload { - public: - IncomingStreamInternalPayload(Payload payload, OutputStream& output_stream) - : InternalPayload(std::move(payload)), output_stream_(&output_stream) {} - - PayloadTransferFrame::PayloadHeader::PayloadType GetType() const override { - return PayloadTransferFrame::PayloadHeader::STREAM; - } - - std::int64_t GetTotalSize() const override { return -1; } - - ByteArray DetachNextChunk() override { return {}; } - - Exception AttachNextChunk(const ByteArray& chunk) override { - if (chunk.Empty()) { - output_stream_->Close(); - return {Exception::kSuccess}; - } - - return output_stream_->Write(chunk); - } - - void Close() override { output_stream_->Close(); } - - private: - OutputStream* output_stream_; -}; - -class OutgoingFileInternalPayload : public InternalPayload { - public: - explicit OutgoingFileInternalPayload(Payload payload) - : InternalPayload(std::move(payload)), - total_size_{payload_.AsFile()->GetTotalSize()} {} - - PayloadTransferFrame::PayloadHeader::PayloadType GetType() const override { - return PayloadTransferFrame::PayloadHeader::FILE; - } - - std::int64_t GetTotalSize() const override { return total_size_; } - - ByteArray DetachNextChunk() override { - InputFile* file = payload_.AsFile(); - if (!file) return {}; - - ExceptionOr bytes_read = file->Read(kChunkSize); - if (!bytes_read.ok()) { - return {}; - } - - ByteArray bytes = std::move(bytes_read.result()); - - if (bytes.Empty()) { - // No more data for outgoing payload. - - file->Close(); - return {}; - } - - return bytes; - } - - Exception AttachNextChunk(const ByteArray& chunk) override { - return {Exception::kIo}; - } - - void Close() override { - InputFile* file = payload_.AsFile(); - if (file) file->Close(); - } - - private: - std::int64_t total_size_; - static constexpr std::int64_t kChunkSize = 64 * 1024; -}; - -class IncomingFileInternalPayload : public InternalPayload { - public: - IncomingFileInternalPayload(Payload payload, OutputFile output_file, - std::int64_t total_size) - : InternalPayload(std::move(payload)), - output_file_(std::move(output_file)), - total_size_(total_size) {} - - PayloadTransferFrame::PayloadHeader::PayloadType GetType() const override { - return PayloadTransferFrame::PayloadHeader::FILE; - } - - std::int64_t GetTotalSize() const override { return total_size_; } - - ByteArray DetachNextChunk() override { return {}; } - - Exception AttachNextChunk(const ByteArray& chunk) override { - if (chunk.Empty()) { - // Received null last chunk for incoming payload. - output_file_.Close(); - return {Exception::kSuccess}; - } - - return output_file_.Write(chunk); - } - - void Close() override { output_file_.Close(); } - - private: - OutputFile output_file_; - const std::int64_t total_size_; -}; - -} // namespace - -std::unique_ptr CreateOutgoingInternalPayload( - Payload payload) { - switch (payload.GetType()) { - case Payload::Type::kBytes: - return absl::make_unique(std::move(payload)); - - case Payload::Type::kFile: { - InputFile* file = payload.AsFile(); - const PayloadId file_payload_id = file ? file->GetPayloadId() : 0; - const PayloadId payload_id = payload.GetId(); - CHECK(payload_id == file_payload_id); - return absl::make_unique(std::move(payload)); - } - - case Payload::Type::kStream: - return absl::make_unique( - std::move(payload)); - - default: - DCHECK(false); // This should never happen. - return {}; - } -} - -std::unique_ptr CreateIncomingInternalPayload( - const PayloadTransferFrame& frame) { - if (frame.packet_type() != PayloadTransferFrame::DATA) { - return {}; - } - - const Payload::Id payload_id = frame.payload_header().id(); - switch (frame.payload_header().type()) { - case PayloadTransferFrame::PayloadHeader::BYTES: { - return absl::make_unique( - Payload(payload_id, ByteArray(frame.payload_chunk().body()))); - } - - case PayloadTransferFrame::PayloadHeader::STREAM: { - auto pipe = std::make_shared(); - - return absl::make_unique( - Payload(payload_id, - [pipe]() -> InputStream& { - return pipe->GetInputStream(); // NOLINT - }), - pipe->GetOutputStream()); - } - - case PayloadTransferFrame::PayloadHeader::FILE: { - std::int64_t total_size = frame.payload_header().total_size(); - return absl::make_unique( - Payload(payload_id, InputFile(payload_id, total_size)), - OutputFile(payload_id), total_size); - } - default: - DCHECK(false); // This should never happen. - return {}; - } -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/internal_payload_factory.h b/cpp/core_v2/internal/internal_payload_factory.h deleted file mode 100644 index b4e64174..00000000 --- a/cpp/core_v2/internal/internal_payload_factory.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef CORE_V2_INTERNAL_INTERNAL_PAYLOAD_FACTORY_H_ -#define CORE_V2_INTERNAL_INTERNAL_PAYLOAD_FACTORY_H_ - -#include "core_v2/internal/internal_payload.h" -#include "core_v2/payload.h" -#include "proto/connections/offline_wire_formats.pb.h" - -namespace location { -namespace nearby { -namespace connections { - -// Creates an InternalPayload representing an outgoing Payload. -std::unique_ptr CreateOutgoingInternalPayload(Payload payload); - -// Creates an InternalPayload representing an incoming Payload from a remote -// endpoint. -std::unique_ptr CreateIncomingInternalPayload( - const PayloadTransferFrame& frame); - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_INTERNAL_PAYLOAD_FACTORY_H_ diff --git a/cpp/core_v2/internal/mediums/BUILD b/cpp/core_v2/internal/mediums/BUILD deleted file mode 100644 index 49ae79f4..00000000 --- a/cpp/core_v2/internal/mediums/BUILD +++ /dev/null @@ -1,91 +0,0 @@ -cc_library( - name = "mediums", - srcs = [ - "ble.cc", - "bloom_filter.cc", - "bluetooth_classic.cc", - "bluetooth_radio.cc", - "mediums.cc", - "uuid.cc", - "webrtc.cc", - "wifi_lan.cc", - ], - hdrs = [ - "ble.h", - "bloom_filter.h", - "bluetooth_classic.h", - "bluetooth_radio.h", - "lost_entity_tracker.h", - "mediums.h", - "uuid.h", - "webrtc.h", - "wifi_lan.h", - ], - visibility = [ - "//core_v2/internal:__subpackages__", - ], - deps = [ - ":utils", - "//core_v2:core_types", - "//core_v2/internal/mediums/ble_v2", - "//core_v2/internal/mediums/webrtc", - "//platform_v2/base", - "//platform_v2/public:comm", - "//platform_v2/public:logging", - "//platform_v2/public:types", - "//location/nearby/mediums/proto:web_rtc_signaling_frames_cc_proto", - "//absl/container:flat_hash_map", - "//absl/container:flat_hash_set", - "//absl/numeric:int128", - "//absl/strings", - "//absl/time", - "//smhasher:libmurmur3", - "//webrtc/api:libjingle_peerconnection_api", - "//webrtc/api:scoped_refptr", - ], -) - -cc_library( - name = "utils", - srcs = ["utils.cc"], - hdrs = ["utils.h"], - visibility = [ - "//core_v2/internal:__pkg__", - "//core_v2/internal/mediums:__pkg__", - "//core_v2/internal/mediums/ble_v2:__pkg__", - "//core_v2/internal/mediums/webrtc:__pkg__", - ], - deps = [ - "//platform_v2/base", - "//platform_v2/public:types", - ], -) - -cc_test( - name = "core_v2_internal_mediums_test", - size = "small", - srcs = [ - "ble_test.cc", - "bloom_filter_test.cc", - "bluetooth_classic_test.cc", - "bluetooth_radio_test.cc", - "lost_entity_tracker_test.cc", - "uuid_test.cc", - "webrtc_test.cc", - "wifi_lan_test.cc", - ], - shard_count = 16, - deps = [ - ":mediums", - "//core_v2/internal/mediums/webrtc", - "//platform_v2/base", - "//platform_v2/base:test_util", - "//platform_v2/impl/g3", # build_cleaner: keep - "//platform_v2/public:comm", - "//platform_v2/public:logging", - "//platform_v2/public:types", - "//testing/base/public:gunit_main", - "//absl/strings", - "//absl/time", - ], -) diff --git a/cpp/core_v2/internal/mediums/ble.cc b/cpp/core_v2/internal/mediums/ble.cc deleted file mode 100644 index 80622a97..00000000 --- a/cpp/core_v2/internal/mediums/ble.cc +++ /dev/null @@ -1,338 +0,0 @@ -#include "core_v2/internal/mediums/ble.h" - -#include -#include -#include - -#include "core_v2/internal/mediums/ble_v2/ble_advertisement.h" -#include "core_v2/internal/mediums/utils.h" -#include "platform_v2/base/prng.h" -#include "platform_v2/public/logging.h" -#include "platform_v2/public/mutex_lock.h" - -namespace location { -namespace nearby { -namespace connections { - -ByteArray Ble::GenerateHash(const std::string& source, size_t size) { - return Utils::Sha256Hash(source, size); -} - -ByteArray Ble::GenerateDeviceToken() { - return Utils::Sha256Hash(std::to_string(Prng().NextUint32()), - mediums::BleAdvertisement::kDeviceTokenLength); -} - -Ble::Ble(BluetoothRadio& radio) : radio_(radio) {} - -bool Ble::IsAvailable() const { - MutexLock lock(&mutex_); - - return IsAvailableLocked(); -} - -bool Ble::IsAvailableLocked() const { return medium_.IsValid(); } - -bool Ble::StartAdvertising(const std::string& service_id, - const ByteArray& advertisement_bytes, - const std::string& fast_advertisement_service_uuid) { - MutexLock lock(&mutex_); - - if (advertisement_bytes.Empty()) { - NEARBY_LOGS(INFO) - << "Refusing to turn on BLE advertising. Empty advertisement data."; - return false; - } - - if (advertisement_bytes.size() > kMaxAdvertisementLength) { - NEARBY_LOG(INFO, - "Refusing to start BLE advertising because the advertisement " - "was too long. Expected at most %d bytes but received %d.", - kMaxAdvertisementLength, advertisement_bytes.size()); - return false; - } - - if (IsAdvertisingLocked(service_id)) { - NEARBY_LOGS(INFO) - << "Failed to BLE advertise because we're already advertising."; - return false; - } - - if (!radio_.IsEnabled()) { - NEARBY_LOGS(INFO) - << "Can't start BLE scanning because Bluetooth was never turned on"; - return false; - } - - if (!IsAvailableLocked()) { - NEARBY_LOGS(INFO) << "Can't turn on BLE advertising. BLE is not available."; - return false; - } - - NEARBY_LOGS(INFO) << "Turning on BLE advertising with advertisement bytes=" - << advertisement_bytes.data() << "(" - << advertisement_bytes.size() << ")" - << ", service id=" << service_id - << ", fast advertisement service uuid=" - << fast_advertisement_service_uuid; - - // Wrap the connections advertisement to the medium advertisement. - const bool fast_advertisement = !fast_advertisement_service_uuid.empty(); - ByteArray service_id_hash{GenerateHash( - service_id, mediums::BleAdvertisement::kServiceIdHashLength)}; - ByteArray medium_advertisement_bytes{mediums::BleAdvertisement{ - mediums::BleAdvertisement::Version::kV2, - mediums::BleAdvertisement::SocketVersion::kV2, - fast_advertisement ? ByteArray{} : service_id_hash, advertisement_bytes, - GenerateDeviceToken()}}; - if (medium_advertisement_bytes.Empty()) { - NEARBY_LOGS(INFO) << "Failed to BLE advertise because we could not " - "create a medium advertisement."; - return false; - } - - if (!medium_.StartAdvertising(service_id, medium_advertisement_bytes, - fast_advertisement_service_uuid)) { - NEARBY_LOGS(INFO) - << "Failed to turn on BLE advertising with advertisement bytes=" - << advertisement_bytes.data() << "(" << advertisement_bytes.size() - << ")" - << ", fast advertisement service uuid=" - << fast_advertisement_service_uuid; - return false; - } - - advertising_info_.Add(service_id); - return true; -} - -bool Ble::StopAdvertising(const std::string& service_id) { - MutexLock lock(&mutex_); - - if (!IsAdvertisingLocked(service_id)) { - NEARBY_LOGS(INFO) << "Can't turn off BLE advertising; it is already off"; - return false; - } - - NEARBY_LOGS(INFO) << "Turned off BLE advertising with service id=" - << service_id; - bool ret = medium_.StopAdvertising(service_id); - // Reset our bundle of advertising state to mark that we're no longer - // advertising. - advertising_info_.Remove(service_id); - return ret; -} - -bool Ble::IsAdvertising(const std::string& service_id) { - MutexLock lock(&mutex_); - - return IsAdvertisingLocked(service_id); -} - -bool Ble::IsAdvertisingLocked(const std::string& service_id) { - return advertising_info_.Existed(service_id); -} - -bool Ble::StartScanning(const std::string& service_id, - const std::string& fast_advertisement_service_uuid, - DiscoveredPeripheralCallback callback) { - MutexLock lock(&mutex_); - - discovered_peripheral_callback_ = std::move(callback); - - if (service_id.empty()) { - NEARBY_LOGS(INFO) - << "Refusing to start BLE scanning with empty service id."; - return false; - } - - if (IsScanningLocked(service_id)) { - NEARBY_LOGS(INFO) << "Refusing to start scan of BLE peripherals because " - "another scanning is already in-progress."; - return false; - } - - if (!radio_.IsEnabled()) { - NEARBY_LOGS(INFO) - << "Can't start BLE scanning because Bluetooth was never turned on"; - return false; - } - - if (!IsAvailableLocked()) { - NEARBY_LOGS(INFO) - << "Can't scan BLE peripherals because BLE isn't available."; - return false; - } - - if (!medium_.StartScanning( - service_id, fast_advertisement_service_uuid, - { - .peripheral_discovered_cb = - [this](BlePeripheral& peripheral, - const std::string& service_id, - const ByteArray& medium_advertisement_bytes, - bool fast_advertisement) { - // Unwrap connection BleAdvertisement from medium - // BleAdvertisement. - auto connection_advertisement_bytes = - UnwrapAdvertisementBytes(medium_advertisement_bytes); - discovered_peripheral_callback_.peripheral_discovered_cb( - peripheral, service_id, connection_advertisement_bytes, - fast_advertisement); - }, - .peripheral_lost_cb = - [this](BlePeripheral& peripheral, - const std::string& service_id) { - discovered_peripheral_callback_.peripheral_lost_cb( - peripheral, service_id); - }, - })) { - NEARBY_LOGS(INFO) << "Failed to start scan of BLE services."; - return false; - } - - NEARBY_LOGS(INFO) << "Turned on BLE scanning with service id=" << service_id; - // Mark the fact that we're currently performing a BLE discovering. - scanning_info_.Add(service_id); - return true; -} - -bool Ble::StopScanning(const std::string& service_id) { - MutexLock lock(&mutex_); - - if (!IsScanningLocked(service_id)) { - NEARBY_LOGS(INFO) << "Can't turn off BLE sacanning because we never " - "started scanning."; - return false; - } - - NEARBY_LOG(INFO, "Turned off BLE scanning with service id=%s", - service_id.c_str()); - bool ret = medium_.StopScanning(service_id); - scanning_info_.Clear(); - return ret; -} - -bool Ble::IsScanning(const std::string& service_id) { - MutexLock lock(&mutex_); - - return IsScanningLocked(service_id); -} - -bool Ble::IsScanningLocked(const std::string& service_id) { - return scanning_info_.Existed(service_id); -} - -bool Ble::StartAcceptingConnections(const std::string& service_id, - AcceptedConnectionCallback callback) { - MutexLock lock(&mutex_); - - if (service_id.empty()) { - NEARBY_LOGS(INFO) - << "Refusing to start accepting BLE connections with empty service id."; - return false; - } - - if (IsAcceptingConnectionsLocked(service_id)) { - NEARBY_LOGS(INFO) - << "Refusing to start accepting BLE connections for " - << service_id - << " because another BLE peripheral socket is already in-progress."; - return false; - } - - if (!radio_.IsEnabled()) { - NEARBY_LOGS(INFO) << "Can't start accepting BLE connections for " - << service_id - << " because Bluetooth isn't enabled."; - return false; - } - - if (!IsAvailableLocked()) { - NEARBY_LOGS(INFO) << "Can't start accepting BLE connections for " - << service_id << " because BLE isn't available."; - return false; - } - - if (!medium_.StartAcceptingConnections(service_id, callback)) { - NEARBY_LOGS(INFO) << "Failed to accept connections callback for " - << service_id << " ."; - return false; - } - - accepting_connections_info_.Add(service_id); - return true; -} - -bool Ble::StopAcceptingConnections(const std::string& service_id) { - MutexLock lock(&mutex_); - - if (!IsAcceptingConnectionsLocked(service_id)) { - NEARBY_LOGS(INFO) - << "Can't stop accepting BLE connections because it was never started."; - return false; - } - - bool ret = medium_.StopAcceptingConnections(service_id); - // Reset our bundle of accepting connections state to mark that we're no - // longer accepting connections. - accepting_connections_info_.Remove(service_id); - return ret; -} - -bool Ble::IsAcceptingConnections(const std::string& service_id) { - MutexLock lock(&mutex_); - - return IsAcceptingConnectionsLocked(service_id); -} - -bool Ble::IsAcceptingConnectionsLocked(const std::string& service_id) { - return accepting_connections_info_.Existed(service_id); -} - -BleSocket Ble::Connect(BlePeripheral& peripheral, - const std::string& service_id) { - MutexLock lock(&mutex_); - NEARBY_LOGS(INFO) << "BLE::Connect: service=" << &peripheral; - // Socket to return. To allow for NRVO to work, it has to be a single object. - BleSocket socket; - - if (service_id.empty()) { - NEARBY_LOGS(INFO) << "Refusing to create BLE socket with empty service_id."; - return socket; - } - - if (!radio_.IsEnabled()) { - NEARBY_LOGS(INFO) << "Can't create client BLE socket to " - << &peripheral << " because Bluetooth isn't enabled."; - return socket; - } - - if (!IsAvailableLocked()) { - NEARBY_LOGS(INFO) << "Can't create client BLE socket [service_id=" - << service_id << "]; BLE isn't available."; - return socket; - } - - socket = medium_.Connect(peripheral, service_id); - if (!socket.IsValid()) { - NEARBY_LOGS(INFO) << "Failed to Connect via BLE [service=" << service_id - << "]"; - } - - return socket; -} - -ByteArray Ble::UnwrapAdvertisementBytes( - const ByteArray& medium_advertisement_data) { - mediums::BleAdvertisement medium_ble_advertisement{medium_advertisement_data}; - if (!medium_ble_advertisement.IsValid()) { - return ByteArray{}; - } - - return medium_ble_advertisement.GetData(); -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/mediums/ble.h b/cpp/core_v2/internal/mediums/ble.h deleted file mode 100644 index b99c07c0..00000000 --- a/cpp/core_v2/internal/mediums/ble.h +++ /dev/null @@ -1,172 +0,0 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_BLE_H_ -#define CORE_V2_INTERNAL_MEDIUMS_BLE_H_ - -#include -#include - -#include "core_v2/internal/mediums/bluetooth_radio.h" -#include "core_v2/listeners.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/public/ble.h" -#include "platform_v2/public/multi_thread_executor.h" -#include "platform_v2/public/mutex.h" -#include "absl/container/flat_hash_map.h" -#include "absl/container/flat_hash_set.h" - -namespace location { -namespace nearby { -namespace connections { - -class Ble { - public: - using DiscoveredPeripheralCallback = BleMedium::DiscoveredPeripheralCallback; - using AcceptedConnectionCallback = BleMedium::AcceptedConnectionCallback; - - explicit Ble(BluetoothRadio& bluetooth_radio); - ~Ble() = default; - - // Returns true, if Ble communications are supported by a platform. - bool IsAvailable() const ABSL_LOCKS_EXCLUDED(mutex_); - - // Sets custom advertisement data, and then enables Ble advertising. - // Returns true, if data is successfully set, and false otherwise. - bool StartAdvertising(const std::string& service_id, - const ByteArray& advertisement_bytes, - const std::string& fast_advertisement_service_uuid) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Disables Ble advertising. - bool StopAdvertising(const std::string& service_id) - ABSL_LOCKS_EXCLUDED(mutex_); - - bool IsAdvertising(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_); - - // Enables Ble scanning mode. Will report any discoverable peripherals in - // range through a callback. Returns true, if scanning mode was enabled, - // false otherwise. - bool StartScanning(const std::string& service_id, - const std::string& fast_advertisement_service_uuid, - DiscoveredPeripheralCallback callback) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Disables Ble discovery mode. - bool StopScanning(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_); - - bool IsScanning(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_); - - // Starts a worker thread, creates a Ble socket, associates it with a - // service id. - bool StartAcceptingConnections(const std::string& service_id, - AcceptedConnectionCallback callback) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Closes socket corresponding to a service id. - bool StopAcceptingConnections(const std::string& service_id) - ABSL_LOCKS_EXCLUDED(mutex_); - - bool IsAcceptingConnections(const std::string& service_id) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns true if this object owns a valid platform implementation. - bool IsMediumValid() const ABSL_LOCKS_EXCLUDED(mutex_) { - MutexLock lock(&mutex_); - return medium_.IsValid(); - } - - // Returns true if this object has a valid BluetoothAdapter reference. - bool IsAdapterValid() const ABSL_LOCKS_EXCLUDED(mutex_) { - MutexLock lock(&mutex_); - return adapter_.IsValid(); - } - - // Establishes connection to Ble peripheral that was might be started on - // another peripheral with StartAcceptingConnections() using the same - // service_id. Blocks until connection is established, or server-side is - // terminated. Returns socket instance. On success, BleSocket.IsValid() return - // true. - BleSocket Connect(BlePeripheral& peripheral, const std::string& service_id) - ABSL_LOCKS_EXCLUDED(mutex_); - - private: - struct AdvertisingInfo { - bool Empty() const { return service_ids.empty(); } - void Clear() { service_ids.clear(); } - void Add(const std::string& service_id) { service_ids.emplace(service_id); } - void Remove(const std::string& service_id) { - service_ids.erase(service_id); - } - bool Existed(const std::string& service_id) const { - return service_ids.contains(service_id); - } - - absl::flat_hash_set service_ids; - }; - - struct ScanningInfo { - bool Empty() const { return service_ids.empty(); } - void Clear() { service_ids.clear(); } - void Add(const std::string& service_id) { service_ids.emplace(service_id); } - void Remove(const std::string& service_id) { - service_ids.erase(service_id); - } - bool Existed(const std::string& service_id) const { - return service_ids.contains(service_id); - } - - absl::flat_hash_set service_ids; - }; - - struct AcceptingConnectionsInfo { - bool Empty() const { return service_ids.empty(); } - void Clear() { service_ids.clear(); } - void Add(const std::string& service_id) { service_ids.emplace(service_id); } - void Remove(const std::string& service_id) { - service_ids.erase(service_id); - } - bool Existed(const std::string& service_id) const { - return service_ids.contains(service_id); - } - - absl::flat_hash_set service_ids; - }; - - static constexpr int kMaxAdvertisementLength = 512; - - static ByteArray GenerateHash(const std::string& source, size_t size); - static ByteArray GenerateDeviceToken(); - - // Same as IsAvailable(), but must be called with mutex_ held. - bool IsAvailableLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Same as IsAdvertising(), but must be called with mutex_ held. - bool IsAdvertisingLocked(const std::string& service_id) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Same as IsDiscovering(), but must be called with mutex_ held. - bool IsScanningLocked(const std::string& service_id) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Same as IsAcceptingConnections(), but must be called with mutex_ held. - bool IsAcceptingConnectionsLocked(const std::string& service_id) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Extract connection advertisement from medium advertisement. - ByteArray UnwrapAdvertisementBytes( - const ByteArray& medium_advertisement_data); - - mutable Mutex mutex_; - BluetoothRadio& radio_ ABSL_GUARDED_BY(mutex_); - BluetoothAdapter& adapter_ ABSL_GUARDED_BY(mutex_){ - radio_.GetBluetoothAdapter()}; - BleMedium medium_ ABSL_GUARDED_BY(mutex_){adapter_}; - AdvertisingInfo advertising_info_ ABSL_GUARDED_BY(mutex_); - ScanningInfo scanning_info_ ABSL_GUARDED_BY(mutex_); - DiscoveredPeripheralCallback discovered_peripheral_callback_; - AcceptingConnectionsInfo accepting_connections_info_ ABSL_GUARDED_BY(mutex_); -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_MEDIUMS_BLE_H_ diff --git a/cpp/core_v2/internal/mediums/bloom_filter.cc b/cpp/core_v2/internal/mediums/bloom_filter.cc deleted file mode 100644 index b2f08fc9..00000000 --- a/cpp/core_v2/internal/mediums/bloom_filter.cc +++ /dev/null @@ -1,91 +0,0 @@ -#include "core_v2/internal/mediums/bloom_filter.h" - -#include "absl/numeric/int128.h" -#include "absl/strings/numbers.h" -#include "smhasher/MurmurHash3.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -BloomFilterBase::BloomFilterBase(const ByteArray& bytes, BitSet* bit_set) - : bits_(bit_set) { - const char* bytes_read_ptr = bytes.data(); - for (size_t byte_index = 0; byte_index < bytes.size(); byte_index++) { - for (size_t bit_index = 0; bit_index < 8; bit_index++) { - bits_->Set((byte_index * 8) + bit_index, - (*bytes_read_ptr >> bit_index) & 0x01); - } - bytes_read_ptr++; - } -} - -BloomFilterBase::operator ByteArray() const { - // Gets a binary string representation of the bitset where the leftmost - // character corresponds to bitset position (total size) - 1. - // - // If the bitset's internal representation is: - // [position 0] 0 0 1 1 0 0 0 1 0 1 0 1 [position 11] - // The string representation will be outputted like this: - // "1 0 1 0 1 0 0 0 1 1 0 0" - std::string bitset_binary_string = bits_->ToString(); - - ByteArray result_bytes(GetMinBytesForBits()); - char* result_bytes_write_ptr = result_bytes.data(); - // We go through the string backwards because the rightmost character - // corresponds to position 0 in the bitset. - for (size_t i = bits_->Size(); i > 0; i -= 8) { - std::string byte_binary_string = bitset_binary_string.substr(i - 8, 8); - std::uint32_t byte_value; - absl::numbers_internal::safe_strtou32_base(byte_binary_string, &byte_value, - /* base= */ 2); - *result_bytes_write_ptr = static_cast(byte_value & 0x000000FF); - result_bytes_write_ptr++; - } - return result_bytes; -} - -void BloomFilterBase::Add(const std::string& s) { - std::vector hashes = GetHashes(s); - for (int32_t hash : hashes) { - size_t position = static_cast(hash) % bits_->Size(); - bits_->Set(position, true); - } -} - -bool BloomFilterBase::PossiblyContains(const std::string& s) { - std::vector hashes = GetHashes(s); - for (int32_t hash : hashes) { - size_t position = static_cast(hash) % bits_->Size(); - if (!bits_->Test(position)) { - return false; - } - } - return true; -} - -std::vector BloomFilterBase::GetHashes(const std::string& s) { - std::vector hashes(kHasherNumberOfRepetitions, 0); - - absl::uint128 hash128; - MurmurHash3_x64_128(s.data(), s.size(), 0, &hash128); - std::uint64_t hash64 = - absl::Uint128Low64(hash128); // the lower 64 bits of the 128-bit hash - std::int32_t hash1 = static_cast( - hash64 & 0x00000000FFFFFFFF); // the lower 32 bits of the 64-bit hash - std::int32_t hash2 = static_cast( - (hash64 >> 32) & 0x0FFFFFFFF); // the upper 32 bits of the 64-bit hash - for (size_t i = 1; i <= kHasherNumberOfRepetitions; i++) { - std::int32_t combinedHash = static_cast(hash1 + (i * hash2)); - // Flip all the bits if it's negative (guaranteed positive number) - if (combinedHash < 0) combinedHash = ~combinedHash; - hashes[i - 1] = combinedHash; - } - return hashes; -} - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/mediums/bloom_filter.h b/cpp/core_v2/internal/mediums/bloom_filter.h deleted file mode 100644 index da65f652..00000000 --- a/cpp/core_v2/internal/mediums/bloom_filter.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_BLOOM_FILTER_H_ -#define CORE_V2_INTERNAL_MEDIUMS_BLOOM_FILTER_H_ - -#include -#include - -#include "platform_v2/base/byte_array.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -/** - * A bloom filter that gives access to the underlying BitSet. The implementation - * is copied from our Java version of Bloom filter, which in turn copies from - * Guava's BloomFilter. - * - * BloomFilter is templatized on the size of the byte array and not the size of - * the bit set to ensure the bit set's length is a multiple of 8 (and can - * neatly be returned as a ByteArray). - */ -class BloomFilterBase { - public: - explicit operator ByteArray() const; - - void Add(const std::string& s); - bool PossiblyContains(const std::string& s); - - protected: - class BitSet { - public: - virtual ~BitSet() = default; - virtual std::string ToString() const = 0; - virtual void Set(size_t pos, bool value) = 0; - virtual bool Test(size_t pos) const = 0; - virtual size_t Size() const = 0; - }; - - BloomFilterBase(const ByteArray& bytes, BitSet* bit_set); - virtual ~BloomFilterBase() = default; - - constexpr static int kHasherNumberOfRepetitions = 5; - std::vector GetHashes(const std::string& s); - - private: - int GetMinBytesForBits() const { return (bits_->Size() + 7) >> 3; } - - BitSet* bits_; -}; - -template -class BloomFilter final : public BloomFilterBase { - public: - BloomFilter() : BloomFilterBase(ByteArray{}, &bits_) {} - explicit BloomFilter(const ByteArray& bytes) - : BloomFilterBase(bytes, &bits_) {} - BloomFilter(const BloomFilter&) = default; - BloomFilter& operator=(const BloomFilter&) = default; - BloomFilter(BloomFilter&& other) : BloomFilterBase(ByteArray{}, &bits_) { - *this = std::move(other); - } - BloomFilter& operator=(BloomFilter&& other) { - std::swap((*this).bits_, other.bits_); - return *this; - } - ~BloomFilter() override = default; - - private: - class BitSetImpl final : public BitSet { - public: - std::string ToString() const override { return bits_.to_string(); } - void Set(size_t pos, bool value) override { bits_.set(pos, value); } - bool Test(size_t pos) const override { return bits_.test(pos); } - size_t Size() const override { return bits_.size(); } - - private: - std::bitset bits_; - } bits_; -}; - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_MEDIUMS_BLOOM_FILTER_H_ diff --git a/cpp/core_v2/internal/mediums/bloom_filter_test.cc b/cpp/core_v2/internal/mediums/bloom_filter_test.cc deleted file mode 100644 index 4464f7f4..00000000 --- a/cpp/core_v2/internal/mediums/bloom_filter_test.cc +++ /dev/null @@ -1,193 +0,0 @@ -#include "core_v2/internal/mediums/bloom_filter.h" - -#include - -#include "gtest/gtest.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { -namespace { - -constexpr size_t kByteArrayLength = 100; - -TEST(BloomFilterTest, EmptyFilterReturnsEmptyArray) { - BloomFilter bloom_filter; - - ByteArray bloom_filter_bytes(bloom_filter); - std::string empty_string(kByteArrayLength, '\0'); - - EXPECT_EQ(empty_string, std::string(bloom_filter_bytes)); -} - -TEST(BloomFilterTest, EmptyFilterNeverContains) { - BloomFilter bloom_filter; - - EXPECT_FALSE(bloom_filter.PossiblyContains("ELEMENT_1")); - EXPECT_FALSE(bloom_filter.PossiblyContains("ELEMENT_2")); - EXPECT_FALSE(bloom_filter.PossiblyContains("ELEMENT_3")); -} - -TEST(BloomFilterTest, AddSuccess) { - BloomFilter bloom_filter; - - EXPECT_FALSE(bloom_filter.PossiblyContains("ELEMENT_1")); - - bloom_filter.Add("ELEMENT_1"); - - EXPECT_TRUE(bloom_filter.PossiblyContains("ELEMENT_1")); -} - -TEST(BloomFilterTest, AddOnlyGivenArg) { - BloomFilter bloom_filter; - - bloom_filter.Add("ELEMENT_1"); - - EXPECT_TRUE(bloom_filter.PossiblyContains("ELEMENT_1")); - EXPECT_FALSE(bloom_filter.PossiblyContains("ELEMENT_2")); - EXPECT_FALSE(bloom_filter.PossiblyContains("ELEMENT_3")); -} - -TEST(BloomFilterTest, AddMultipleArgs) { - BloomFilter bloom_filter; - - bloom_filter.Add("ELEMENT_1"); - bloom_filter.Add("ELEMENT_2"); - - EXPECT_TRUE(bloom_filter.PossiblyContains("ELEMENT_1")); - EXPECT_TRUE(bloom_filter.PossiblyContains("ELEMENT_2")); - EXPECT_FALSE(bloom_filter.PossiblyContains("ELEMENT_3")); -} - -TEST(BloomFilterTest, AddMultipleArgsReturnsNonemptyArray) { - BloomFilter<10> bloom_filter; - - bloom_filter.Add("ELEMENT_1"); - bloom_filter.Add("ELEMENT_2"); - bloom_filter.Add("ELEMENT_3"); - - ByteArray bloom_filter_bytes(bloom_filter); - std::string empty_string(kByteArrayLength, '\0'); - - EXPECT_NE(std::string(bloom_filter_bytes), empty_string); -} - -TEST(BloomFilterTest, CopyConstructorAndAssignmentSuccess) { - BloomFilter bloom_filter; - - EXPECT_FALSE(bloom_filter.PossiblyContains("ELEMENT_1")); - - bloom_filter.Add("ELEMENT_1"); - - BloomFilter bloom_filter_copy_1{bloom_filter}; - BloomFilter bloom_filter_copy_2 = bloom_filter; - - EXPECT_TRUE(bloom_filter.PossiblyContains("ELEMENT_1")); - EXPECT_TRUE(bloom_filter_copy_1.PossiblyContains("ELEMENT_1")); - EXPECT_TRUE(bloom_filter_copy_2.PossiblyContains("ELEMENT_1")); -} - -TEST(BloomFilterTest, MoveConstructorSuccess) { - BloomFilter bloom_filter; - - bloom_filter.Add("ELEMENT_1"); - - BloomFilter bloom_filter_move{std::move(bloom_filter)}; - - EXPECT_TRUE(bloom_filter_move.PossiblyContains("ELEMENT_1")); -} - -TEST(BloomFilterTest, MoveAssignmentSuccess) { - BloomFilter bloom_filter; - - bloom_filter.Add("ELEMENT_1"); - - BloomFilter bloom_filter_move = std::move(bloom_filter); - - EXPECT_TRUE(bloom_filter_move.PossiblyContains("ELEMENT_1")); -} - -/** - * This test was added because of a bug where the BloomFilter doesn't utilize - * all bits given. Functionally, the filter still works, but we just have a much - * higher false positive rate. The bug was caused by confusing bit length and - * byte length, which made our BloomFilter only set bits on the first byteLength - * (bitLength / 8) bits rather than the whole bitLength bits. - * - *

Here, we're verifying that the bits set are somewhat scattered. So instead - * of something like [ 0, 1, 1, 0, 0, 0, 0, ..., 0 ], we should be getting - * something like [ 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, ..., 1, 0]. - */ -TEST(BloomFilterTest, RandomnessNoEndBias) { - BloomFilter bloom_filter; - - // Add one element to our BloomFilter. - bloom_filter.Add("ELEMENT_1"); - - std::int32_t non_zero_count = 0; - std::int32_t longest_zero_streak = 0; - std::int32_t current_zero_streak = 0; - - // Record the amount of non-zero bytes and the longest streak of zero bytes in - // the resulting BloomFilter. This is an approximation of reasonable - // distribution since we're recording by bytes instead of bits. - ByteArray bloom_filter_bytes(bloom_filter); - const char* bloom_filter_bytes_read_ptr = bloom_filter_bytes.data(); - for (int i = 0; i < bloom_filter_bytes.size(); i++) { - if (*bloom_filter_bytes_read_ptr == '\0') { - current_zero_streak++; - } else { - // Increment the number of non-zero bytes we've seen, update the longest - // zero streak, and then reset the current zero streak. - non_zero_count++; - longest_zero_streak = std::max(longest_zero_streak, current_zero_streak); - current_zero_streak = 0; - } - bloom_filter_bytes_read_ptr++; - } - // Update the longest zero streak again for the tail case. - longest_zero_streak = std::min(longest_zero_streak, current_zero_streak); - - // Since randomness is hard to measure within one unit test, we instead do a - // sanity check. All non-zero bytes should not be packed into one end of the - // array. - // - // In this case, the size of one end is approximated to be: - // kByteArrayLength / nonZeroCount. - // Therefore, the longest zero streak should be less than: - // kByteArrayLength - one end of the array. - std::int32_t longest_acceptable_zero_streak = - kByteArrayLength - (kByteArrayLength / non_zero_count); - - EXPECT_TRUE(longest_zero_streak <= longest_acceptable_zero_streak); -} - -TEST(BloomFilterTest, RandomnessFalsePositiveRate) { - BloomFilter<10> bloom_filter; - - // Add 5 distinct elements to the BloomFilter. - bloom_filter.Add("ELEMENT_1"); - bloom_filter.Add("ELEMENT_2"); - bloom_filter.Add("ELEMENT_3"); - bloom_filter.Add("ELEMENT_4"); - bloom_filter.Add("ELEMENT_5"); - - std::int32_t false_positives = 0; - // Now test 100 other elements and record the number of false positives. - for (int i = 5; i < 105; i++) { - false_positives += - bloom_filter.PossiblyContains("ELEMENT_" + std::to_string(i)) ? 1 : 0; - } - - // We expect the false positive rate to be 3% with 5 elements in a 10 byte - // filter. Thus, we give a little leeway and verify that the false positive - // rate is no more than 5%. - EXPECT_LE(false_positives, 5); -} - -} // namespace -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/mediums/bluetooth_classic.cc b/cpp/core_v2/internal/mediums/bluetooth_classic.cc deleted file mode 100644 index 15dad66c..00000000 --- a/cpp/core_v2/internal/mediums/bluetooth_classic.cc +++ /dev/null @@ -1,388 +0,0 @@ -#include "core_v2/internal/mediums/bluetooth_classic.h" - -#include -#include -#include - -#include "core_v2/internal/mediums/uuid.h" -#include "platform_v2/public/logging.h" -#include "platform_v2/public/mutex_lock.h" - -namespace location { -namespace nearby { -namespace connections { - -BluetoothClassic::BluetoothClassic(BluetoothRadio& radio) : radio_(radio) {} - -BluetoothClassic::~BluetoothClassic() { - // Destructor is not taking locks, but methods it is calling are. - StopDiscovery(); - while (!server_sockets_.empty()) { - StopAcceptingConnections(server_sockets_.begin()->first); - } - TurnOffDiscoverability(); - - // All the AcceptLoopRunnable objects in here should already have gotten an - // opportunity to shut themselves down cleanly in the calls to - // StopAcceptingConnections() above. - accept_loops_runner_.Shutdown(); -} - -bool BluetoothClassic::IsAvailable() const { - MutexLock lock(&mutex_); - - return IsAvailableLocked(); -} - -bool BluetoothClassic::IsAvailableLocked() const { - return medium_.IsValid() && adapter_.IsValid(); -} - -bool BluetoothClassic::TurnOnDiscoverability(const std::string& device_name) { - MutexLock lock(&mutex_); - - if (device_name.empty()) { - NEARBY_LOG(INFO, - "Refusing to turn on BT discoverability. Empty device name."); - return false; - } - - if (!radio_.IsEnabled()) { - NEARBY_LOG(INFO, "Can't turn on BT discoverability. BT is off."); - return false; - } - - if (!IsAvailableLocked()) { - NEARBY_LOG(INFO, "Can't turn on BT discoverability. BT is not available."); - return false; - } - - if (IsDiscoverable()) { - NEARBY_LOG(INFO, - "Refusing to turn on BT discoverability; new name='%s'; " - "current name='%s'", - device_name.c_str(), adapter_.GetName().c_str()); - return false; - } - - if (!ModifyDeviceName(device_name)) { - NEARBY_LOG(INFO, - "Failed to turn on BT discoverability; " - "failed to set name to %s", - device_name.c_str()); - return false; - } - - if (!ModifyScanMode(ScanMode::kConnectableDiscoverable)) { - NEARBY_LOG(INFO, - "Failed to turn on BT discoverability; " - "failed to set scan_mode to %d", - ScanMode::kConnectableDiscoverable); - - // Don't forget to perform this rollback of the partial state changes we've - // made til now. - RestoreDeviceName(); - return false; - } - - NEARBY_LOG(INFO, "Turned on BT discoverability with device_name=%s", - device_name.c_str()); - return true; -} - -bool BluetoothClassic::TurnOffDiscoverability() { - MutexLock lock(&mutex_); - - if (!IsDiscoverable()) { - NEARBY_LOG(INFO, "Can't turn off BT discoverability; it is already off"); - return false; - } - - RestoreScanMode(); - RestoreDeviceName(); - - NEARBY_LOG(INFO, "Turned Bluetooth discoverability off"); - return true; -} - -bool BluetoothClassic::IsDiscoverable() const { - return (!original_device_name_.empty() && - (adapter_.GetScanMode() == ScanMode::kConnectableDiscoverable)); -} - -bool BluetoothClassic::ModifyDeviceName(const std::string& device_name) { - if (original_device_name_.empty()) { - original_device_name_ = adapter_.GetName(); - } - - return adapter_.SetName(device_name); -} - -bool BluetoothClassic::ModifyScanMode(ScanMode scan_mode) { - if (original_scan_mode_ == ScanMode::kUnknown) { - original_scan_mode_ = adapter_.GetScanMode(); - } - - if (!adapter_.SetScanMode(scan_mode)) { - original_scan_mode_ = ScanMode::kUnknown; - return false; - } - - return true; -} - -bool BluetoothClassic::RestoreScanMode() { - if (original_scan_mode_ == ScanMode::kUnknown || - !adapter_.SetScanMode(original_scan_mode_)) { - NEARBY_LOG(INFO, "Failed to restore original Bluetooth scan mode to %d", - original_scan_mode_); - return false; - } - - // Regardless of whether or not we could actually restore the Bluetooth scan - // mode, reset our relevant state. - original_scan_mode_ = ScanMode::kUnknown; - return true; -} - -bool BluetoothClassic::RestoreDeviceName() { - if (original_device_name_.empty() || - !adapter_.SetName(original_device_name_)) { - NEARBY_LOG(INFO, "Failed to restore original Bluetooth device name to %s", - original_device_name_.c_str()); - return false; - } - original_device_name_.clear(); - return true; -} - -bool BluetoothClassic::StartDiscovery(DiscoveredDeviceCallback callback) { - MutexLock lock(&mutex_); - - if (!radio_.IsEnabled()) { - NEARBY_LOG(INFO, "Can't discover BT devices because BT isn't enabled."); - return false; - } - - if (!IsAvailableLocked()) { - NEARBY_LOG(INFO, "Can't discover BT devices because BT isn't available."); - return false; - } - - if (IsDiscovering()) { - NEARBY_LOG(INFO, - "Refusing to start discovery of BT devices because another " - "discovery is already in-progress."); - return false; - } - - if (!medium_.StartDiscovery(callback)) { - NEARBY_LOG(INFO, "Failed to start discovery of BT devices."); - return false; - } - - // Mark the fact that we're currently performing a Bluetooth scan. - scan_info_.valid = true; - - return true; -} - -bool BluetoothClassic::StopDiscovery() { - MutexLock lock(&mutex_); - - if (!IsDiscovering()) { - NEARBY_LOG(INFO, - "Can't stop discovery of BT devices because it never started."); - return false; - } - - if (!medium_.StopDiscovery()) { - NEARBY_LOG(INFO, "Failed to stop discovery of Bluetooth devices."); - return false; - } - - scan_info_.valid = false; - return true; -} - -bool BluetoothClassic::IsDiscovering() const { return scan_info_.valid; } - -bool BluetoothClassic::StartAcceptingConnections( - const std::string& service_name, AcceptedConnectionCallback callback) { - MutexLock lock(&mutex_); - - if (service_name.empty()) { - NEARBY_LOG( - INFO, - "Refusing to start accepting BT connections; service name is empty."); - return false; - } - - if (!radio_.IsEnabled()) { - NEARBY_LOG(INFO, - "Can't create BT server socket [service=%s]; BT is disabled.", - service_name.c_str()); - return false; - } - - if (!IsAvailableLocked()) { - NEARBY_LOG( - INFO, - "Can't start accepting BT connections [service=%s]; BT not available.", - service_name.c_str()); - return false; - } - - if (IsAcceptingConnectionsLocked(service_name)) { - NEARBY_LOG(INFO, - "Refusing to start accepting BT connections [service=%s]; BT " - "server is already in-progress with the same name.", - service_name.c_str()); - return false; - } - - BluetoothServerSocket socket = medium_.ListenForService( - service_name, GenerateUuidFromString(service_name)); - if (!socket.IsValid()) { - NEARBY_LOG(INFO, "Failed to start accepting Bluetooth connections for %s.", - service_name.c_str()); - return false; - } - - // Mark the fact that there's an in-progress Bluetooth server accepting - // connections. - auto owned_socket = - server_sockets_.emplace(service_name, std::move(socket)).first->second; - - // Start the accept loop on a dedicated thread - this stays alive and - // listening for new incoming connections until StopAcceptingConnections() is - // invoked. - accept_loops_runner_.Execute([callback = std::move(callback), - server_socket = std::move(owned_socket), - service_name]() mutable { - while (true) { - BluetoothSocket client_socket = server_socket.Accept(); - if (!client_socket.IsValid()) { - server_socket.Close(); - break; - } - - callback.accepted_cb(std::move(client_socket)); - } - }); - - return true; -} - -bool BluetoothClassic::IsAcceptingConnections(const std::string& service_name) { - MutexLock lock(&mutex_); - - return IsAcceptingConnectionsLocked(service_name); -} - -bool BluetoothClassic::IsAcceptingConnectionsLocked( - const std::string& service_name) { - return server_sockets_.find(service_name) != server_sockets_.end(); -} - -bool BluetoothClassic::StopAcceptingConnections( - const std::string& service_name) { - MutexLock lock(&mutex_); - - if (service_name.empty()) { - NEARBY_LOG(INFO, - "Unable to stop accepting BT connections because the " - "service_name is empty."); - return false; - } - - const auto& it = server_sockets_.find(service_name); - if (it == server_sockets_.end()) { - NEARBY_LOG(INFO, - "Can't stop accepting BT connections for %s because it was " - "never started.", - service_name.c_str()); - return false; - } - - // Closing the BluetoothServerSocket will kick off the suicide of the thread - // in accept_loops_thread_pool_ that blocks on BluetoothServerSocket.accept(). - // That may take some time to complete, but there's no particular reason to - // wait around for it. - auto item = server_sockets_.extract(it); - - // Store a handle to the BluetoothServerSocket, so we can use it after - // removing the entry from server_sockets_; making it scoped - // is a bonus that takes care of deallocation before we leave this method. - BluetoothServerSocket& listening_socket = item.mapped(); - - // Regardless of whether or not we fail to close the existing - // BluetoothServerSocket, remove it from server_sockets_ so that it - // frees up this service for another round. - - // Finally, close the BluetoothServerSocket. - if (!listening_socket.Close().Ok()) { - NEARBY_LOG(INFO, "Failed to close BT server socket for %s.", - service_name.c_str()); - return false; - } - - return true; -} - -BluetoothSocket BluetoothClassic::Connect(BluetoothDevice& bluetooth_device, - const std::string& service_name) { - MutexLock lock(&mutex_); - NEARBY_LOG(INFO, "BluetoothClassic::Connect: device=%p", &bluetooth_device); - // Socket to return. To allow for NRVO to work, it has to be a single object. - BluetoothSocket socket; - - if (service_name.empty()) { - NEARBY_LOG( - INFO, - "Refusing to create client BT socket because service_name is empty."); - return socket; - } - - if (!radio_.IsEnabled()) { - NEARBY_LOG(INFO, - "Can't create client BT socket [service=%s]: BT isn't enabled.", - service_name.c_str()); - return socket; - } - - if (!IsAvailableLocked()) { - NEARBY_LOG( - INFO, "Can't create client BT socket [service=%s]; BT isn't available.", - service_name.c_str()); - return socket; - } - - socket = medium_.ConnectToService(bluetooth_device, - GenerateUuidFromString(service_name)); - if (!socket.IsValid()) { - NEARBY_LOG(INFO, "Failed to Connect via BT [service=%s]", - service_name.c_str()); - } - - return socket; -} - -BluetoothDevice BluetoothClassic::GetRemoteDevice( - const std::string& mac_address) { - MutexLock lock(&mutex_); - return medium_.GetRemoteDevice(mac_address); -} - -std::string BluetoothClassic::GetMacAddress() const { - MutexLock lock(&mutex_); - return medium_.GetMacAddress(); -} - -std::string BluetoothClassic::GenerateUuidFromString(const std::string& data) { - return std::string(Uuid(data)); -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/mediums/bluetooth_classic.h b/cpp/core_v2/internal/mediums/bluetooth_classic.h deleted file mode 100644 index 29ae73e5..00000000 --- a/cpp/core_v2/internal/mediums/bluetooth_classic.h +++ /dev/null @@ -1,183 +0,0 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_BLUETOOTH_CLASSIC_H_ -#define CORE_V2_INTERNAL_MEDIUMS_BLUETOOTH_CLASSIC_H_ - -#include -#include - -#include "core_v2/internal/mediums/bluetooth_radio.h" -#include "core_v2/listeners.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/public/bluetooth_adapter.h" -#include "platform_v2/public/bluetooth_classic.h" -#include "platform_v2/public/multi_thread_executor.h" -#include "platform_v2/public/mutex.h" -#include "absl/container/flat_hash_map.h" - -namespace location { -namespace nearby { -namespace connections { - -class BluetoothClassic { - public: - using DiscoveredDeviceCallback = BluetoothClassicMedium::DiscoveryCallback; - using ScanMode = BluetoothAdapter::ScanMode; - - // Callback that is invoked when a new connection is accepted. - struct AcceptedConnectionCallback { - std::function accepted_cb = - DefaultCallback(); - }; - - explicit BluetoothClassic(BluetoothRadio& bluetooth_radio); - ~BluetoothClassic(); - - // Returns true, if BT communications are supported by a platform. - bool IsAvailable() const ABSL_LOCKS_EXCLUDED(mutex_); - - // Sets custom device name, and then enables BT discoverable mode. - // Returns true, if name and scan mode are successfully set, and false - // otherwise. - // Called by server. - bool TurnOnDiscoverability(const std::string& device_name) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Disables BT discoverability, and restores scan mode and device name to - // what they were before the call to TurnOnDiscoverability(). - // Returns false if no successful call TurnOnDiscoverability() was previously - // made, otherwise returns true. - // Called by server. - bool TurnOffDiscoverability() ABSL_LOCKS_EXCLUDED(mutex_); - - // Enables BT discovery mode. Will report any discoverable devices in range - // through a callback. - // Returns true, if discovery mode was enabled, false otherwise. - // Called by client. - bool StartDiscovery(DiscoveredDeviceCallback callback) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Disables BT discovery mode. - // Returns true, if discovery mode was previously enabled, false otherwise. - // Called by client. - bool StopDiscovery() ABSL_LOCKS_EXCLUDED(mutex_); - - // Starts a worker thread, creates a BT server socket, associates it with a - // service name; in a worker thread repeatedly calls ServerSocket::Accept(). - // Any connected sockets returned from Accept() are passed to a callback. - // Returns true, if server socket was successfully created, false otherwise. - // Called by server. - bool StartAcceptingConnections(const std::string& service_name, - AcceptedConnectionCallback callback) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns true, if object is currently running a Accept() loop. - bool IsAcceptingConnections(const std::string& service_name) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Closes server socket corresponding to a service name. This automatically - // terminates Accept() loop, if it were running. - // Called by server. - bool StopAcceptingConnections(const std::string& service_name) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns true if this object owns a valid platform implementation. - bool IsMediumValid() const ABSL_LOCKS_EXCLUDED(mutex_) { - MutexLock lock(&mutex_); - return medium_.IsValid(); - } - - // Returns true if this object has a valid BluetoothAdapter reference. - bool IsAdapterValid() const ABSL_LOCKS_EXCLUDED(mutex_) { - MutexLock lock(&mutex_); - return adapter_.IsValid(); - } - - // Establishes connection to BT service that was might be started on another - // device with StartAcceptingConnections() using the same service_name. - // Blocks until connection is established, or server-side is terminated. - // Returns socket instance. On success, BluetoothSocket.IsValid() return true. - // Called by client. - BluetoothSocket Connect(BluetoothDevice& bluetooth_device, - const std::string& service_name) - ABSL_LOCKS_EXCLUDED(mutex_); - - std::string GetMacAddress() const ABSL_LOCKS_EXCLUDED(mutex_); - - BluetoothDevice GetRemoteDevice(const std::string& mac_address) - ABSL_LOCKS_EXCLUDED(mutex_); - - private: - struct ScanInfo { - bool valid = false; - }; - - static constexpr int kMaxConcurrentAcceptLoops = 5; - - // Constructs UUID object from arbitrary string, using MD5 hash, and then - // converts UUID to a readable UUID string and returns it. - static std::string GenerateUuidFromString(const std::string& data); - - // Same as IsAvailable(), but must be called with mutex_ held. - bool IsAvailableLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Same as IsAcceptingConnections(), but must be called with mutex_ held. - bool IsAcceptingConnectionsLocked(const std::string& service_name) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Returns true, if discoverability is enabled with TurnOnDiscoverability(). - bool IsDiscoverable() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Assignes a different name to BT adapter. - // Returns true if successful. Stores original device name. - bool ModifyDeviceName(const std::string& device_name) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Changes current scan mode. This is an implementation of - // TurnDiscoveradility() method. Stores original scan mode. - bool ModifyScanMode(ScanMode scan_mode) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Restores original device name (the one before the very first call to - // ModifyDeviceName()). Returns true if successful. - bool RestoreScanMode() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Restores original device scan mode (the one before the very first call to - // ModifyScanMode()). Returns true if successful. - bool RestoreDeviceName() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Returns true if device is currently in discovery mode. - bool IsDiscovering() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - mutable Mutex mutex_; - BluetoothRadio& radio_ ABSL_GUARDED_BY(mutex_); - BluetoothAdapter& adapter_ ABSL_GUARDED_BY(mutex_){ - radio_.GetBluetoothAdapter()}; - BluetoothClassicMedium medium_ ABSL_GUARDED_BY(mutex_){adapter_}; - - // A bundle of state required to do a Bluetooth Classic scan. When non-null, - // we are currently performing a Bluetooth scan. - ScanInfo scan_info_ ABSL_GUARDED_BY(mutex_); - - // The original scan mode (that controls visibility to scanners) of the device - // before we modified it. Restored when we stop advertising. - ScanMode original_scan_mode_ ABSL_GUARDED_BY(mutex_) = ScanMode::kUnknown; - - // The original Bluetooth device name, before we modified it. If non-empty, we - // are currently Bluetooth discoverable. Restored when we stop advertising. - std::string original_device_name_ ABSL_GUARDED_BY(mutex_); - - // A thread pool dedicated to running all the accept loops from - // StartAcceptingConnections(). - MultiThreadExecutor accept_loops_runner_{kMaxConcurrentAcceptLoops}; - - // A map of service Name -> ServerSocket. If map is non-empty, we - // are currently listening for incoming connections. - // BluetoothServerSocket instances are used from accept_loops_runner_, - // and thus require pointer stability. - absl::flat_hash_map server_sockets_ - ABSL_GUARDED_BY(mutex_); -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_MEDIUMS_BLUETOOTH_CLASSIC_H_ diff --git a/cpp/core_v2/internal/mediums/bluetooth_radio.cc b/cpp/core_v2/internal/mediums/bluetooth_radio.cc deleted file mode 100644 index c7a650a4..00000000 --- a/cpp/core_v2/internal/mediums/bluetooth_radio.cc +++ /dev/null @@ -1,106 +0,0 @@ -#include "core_v2/internal/mediums/bluetooth_radio.h" - -#include "platform_v2/base/exception.h" -#include "platform_v2/public/logging.h" -#include "platform_v2/public/system_clock.h" - -namespace location { -namespace nearby { -namespace connections { - -constexpr absl::Duration BluetoothRadio::kPauseBetweenToggle; - -BluetoothRadio::BluetoothRadio() { - if (!IsAdapterValid()) { - NEARBY_LOG(ERROR, "Bluetooth adapter is not valid: BT is not supported"); - } -} - -BluetoothRadio::~BluetoothRadio() { - // We never enabled Bluetooth, nothing to do. - if (!ever_saved_state_.Get()) { - NEARBY_LOG(INFO, "BT adapter was not used. Not touching HW."); - return; - } - - // Toggle Bluetooth regardless of our original state. Some devices/chips can - // start to freak out after some time (e.g. b/37775337), and this helps to - // ensure BT resets properly. - NEARBY_LOG(INFO, "Toggle BT adapter state before releasing adapter."); - Toggle(); - - NEARBY_LOG(INFO, "Bring BT adapter to original state"); - if (!SetBluetoothState(originally_enabled_.Get())) { - NEARBY_LOG(INFO, "Failed to restore BT adapter original state."); - } -} - -bool BluetoothRadio::Enable() { - if (!SaveOriginalState()) { - return false; - } - - return SetBluetoothState(true); -} - -bool BluetoothRadio::Disable() { - if (!SaveOriginalState()) { - return false; - } - - return SetBluetoothState(false); -} - -bool BluetoothRadio::IsEnabled() const { - return IsAdapterValid() && IsInDesiredState(true); -} - -bool BluetoothRadio::Toggle() { - if (!SaveOriginalState()) { - return false; - } - - if (!SetBluetoothState(false)) { - NEARBY_LOG(INFO, "BT Toggle: Failed to turn BT off."); - return false; - } - - if (SystemClock::Sleep(kPauseBetweenToggle).Raised(Exception::kInterrupted)) { - NEARBY_LOG(INFO, "BT Toggle: interrupted before turing on."); - return false; - } - - if (!SetBluetoothState(true)) { - NEARBY_LOG(INFO, "BT Toggle: Failed to turn BT on."); - return false; - } - - return true; -} - -bool BluetoothRadio::SetBluetoothState(bool enable) { - return bluetooth_adapter_.SetStatus( - enable ? BluetoothAdapter::Status::kEnabled - : BluetoothAdapter::Status::kDisabled); -} - -bool BluetoothRadio::IsInDesiredState(bool should_be_enabled) const { - return bluetooth_adapter_.IsEnabled() == should_be_enabled; -} - -bool BluetoothRadio::SaveOriginalState() { - if (!IsAdapterValid()) { - return false; - } - - // If we haven't saved the original state of the radio, save it. - if (!ever_saved_state_.Set(true)) { - originally_enabled_.Set(bluetooth_adapter_.IsEnabled()); - } - - return true; -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/mediums/bluetooth_radio.h b/cpp/core_v2/internal/mediums/bluetooth_radio.h deleted file mode 100644 index ebec1881..00000000 --- a/cpp/core_v2/internal/mediums/bluetooth_radio.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_BLUETOOTH_RADIO_H_ -#define CORE_V2_INTERNAL_MEDIUMS_BLUETOOTH_RADIO_H_ - -#include - -#include "platform_v2/public/atomic_boolean.h" -#include "platform_v2/public/bluetooth_adapter.h" -#include "absl/time/clock.h" - -namespace location { -namespace nearby { -namespace connections { - -// Provides the operations that can be performed on the Bluetooth radio. -class BluetoothRadio { - public: - BluetoothRadio(); - BluetoothRadio(BluetoothRadio&&) = default; - BluetoothRadio& operator=(BluetoothRadio&&) = default; - - // Reverts the Bluetooth radio to its original state. - ~BluetoothRadio(); - - // Enables Bluetooth. - // - // This must be called before attempting to invoke any other methods of - // this class. - // - // Returns true if enabled successfully. - bool Enable(); - - // Disables Bluetooth. - // - // Returns true if disabled successfully. - bool Disable(); - - // Returns true if the Bluetooth radio is currently enabled. - bool IsEnabled() const; - - // Turn BT radio Off, delay for kPauseBetweenToggle and then turn it On. - // This will block calling thread for at least kPauseBetweenToggle duration. - bool Toggle(); - - // Returns result of BluetoothAdapter::IsValid() for private adapter instance. - bool IsAdapterValid() const { - return bluetooth_adapter_.IsValid(); - } - - BluetoothAdapter& GetBluetoothAdapter() { - return bluetooth_adapter_; - } - - private: - static constexpr absl::Duration kPauseBetweenToggle = absl::Seconds(3); - - bool SetBluetoothState(bool enable); - bool IsInDesiredState(bool should_be_enabled) const; - // To be called in enable(), disable(), and toggle(). This will remember the - // original state of the radio before any radio state has been modified. - // Returns false if Bluetooth doesn't exist on the device and the state cannot - // be obtained. - bool SaveOriginalState(); - - // BluetoothAdapter::IsValid() will return false if BT is not supported. - BluetoothAdapter bluetooth_adapter_; - - // The Bluetooth radio's original state, before we modified it. True if - // originally enabled, false if originally disabled. - // We restore the radio to its original state in the destructor. - - AtomicBoolean originally_enabled_{false}; - // false if we never modified the radio state, true otherwise. - AtomicBoolean ever_saved_state_{false}; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_MEDIUMS_BLUETOOTH_RADIO_H_ diff --git a/cpp/core_v2/internal/mediums/lost_entity_tracker.h b/cpp/core_v2/internal/mediums/lost_entity_tracker.h deleted file mode 100644 index e83b21f1..00000000 --- a/cpp/core_v2/internal/mediums/lost_entity_tracker.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_LOST_ENTITY_TRACKER_H_ -#define CORE_V2_INTERNAL_MEDIUMS_LOST_ENTITY_TRACKER_H_ - -#include "platform_v2/public/mutex.h" -#include "platform_v2/public/mutex_lock.h" -#include "absl/container/flat_hash_set.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -// Tracks "lost" entities based on a manual update/compute model. Used by -// mediums that only report found devices. Lost entities are computed based off -// of whether a specific entity was rediscovered since the last call to -// ComputeLostEntities. -// -// Note: Entity must overload the < and == operators. -template -class LostEntityTracker { - public: - using EntitySet = absl::flat_hash_set; - - LostEntityTracker(); - ~LostEntityTracker(); - - // Records the given entity as being recently found, whether or not this is - // our first time discovering the entity. - void RecordFoundEntity(const Entity& entity) ABSL_LOCKS_EXCLUDED(mutex_); - - // Computes and returns the set of entities considered lost since the last - // time this method was called. - EntitySet ComputeLostEntities() ABSL_LOCKS_EXCLUDED(mutex_); - - private: - Mutex mutex_; - EntitySet current_entities_ ABSL_GUARDED_BY(mutex_); - EntitySet previously_found_entities_ ABSL_GUARDED_BY(mutex_); -}; - -template -LostEntityTracker::LostEntityTracker() - : current_entities_{}, previously_found_entities_{} {} - -template -LostEntityTracker::~LostEntityTracker() { - previously_found_entities_.clear(); - current_entities_.clear(); -} - -template -void LostEntityTracker::RecordFoundEntity(const Entity& entity) { - MutexLock lock(&mutex_); - - current_entities_.insert(entity); -} - -template -typename LostEntityTracker::EntitySet -LostEntityTracker::ComputeLostEntities() { - MutexLock lock(&mutex_); - - // The set of lost entities is the previously found set MINUS the currently - // found set. - for (const auto& item : current_entities_) { - previously_found_entities_.erase(item); - } - auto lost_entities = std::move(previously_found_entities_); - previously_found_entities_ = std::move(current_entities_); - current_entities_ = {}; - - return lost_entities; -} - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_MEDIUMS_LOST_ENTITY_TRACKER_H_ diff --git a/cpp/core_v2/internal/mediums/lost_entity_tracker_test.cc b/cpp/core_v2/internal/mediums/lost_entity_tracker_test.cc deleted file mode 100644 index 829aaadf..00000000 --- a/cpp/core_v2/internal/mediums/lost_entity_tracker_test.cc +++ /dev/null @@ -1,123 +0,0 @@ -#include "core_v2/internal/mediums/lost_entity_tracker.h" - -#include "gtest/gtest.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { -namespace { - -struct TestEntity { - int id; - - template - friend H AbslHashValue(H h, const TestEntity& test_entity) { - return H::combine(std::move(h), test_entity.id); - } - - bool operator==(const TestEntity& other) const { return id == other.id; } - bool operator<(const TestEntity& other) const { return id < other.id; } -}; - -TEST(LostEntityTrackerTest, NoEntitiesLost) { - LostEntityTracker lost_entity_tracker; - TestEntity entity_1{1}; - TestEntity entity_2{2}; - TestEntity entity_3{3}; - - // Discover some entities. - lost_entity_tracker.RecordFoundEntity(entity_1); - lost_entity_tracker.RecordFoundEntity(entity_2); - lost_entity_tracker.RecordFoundEntity(entity_3); - - // Make sure none are lost on the first round. - ASSERT_TRUE(lost_entity_tracker.ComputeLostEntities().empty()); - - // Rediscover the same entities. - lost_entity_tracker.RecordFoundEntity(entity_1); - lost_entity_tracker.RecordFoundEntity(entity_2); - lost_entity_tracker.RecordFoundEntity(entity_3); - - // Make sure we still didn't lose any entities. - EXPECT_TRUE(lost_entity_tracker.ComputeLostEntities().empty()); -} - -TEST(LostEntityTrackerTest, AllEntitiesLost) { - LostEntityTracker lost_entity_tracker; - TestEntity entity_1{1}; - TestEntity entity_2{2}; - TestEntity entity_3{3}; - - // Discover some entities. - lost_entity_tracker.RecordFoundEntity(entity_1); - lost_entity_tracker.RecordFoundEntity(entity_2); - lost_entity_tracker.RecordFoundEntity(entity_3); - - // Make sure none are lost on the first round. - EXPECT_TRUE(lost_entity_tracker.ComputeLostEntities().empty()); - - // Go through a round without rediscovering any entities. - typename LostEntityTracker::EntitySet lost_entities = - lost_entity_tracker.ComputeLostEntities(); - EXPECT_TRUE(lost_entities.find(entity_1) != lost_entities.end()); - EXPECT_TRUE(lost_entities.find(entity_2) != lost_entities.end()); - EXPECT_TRUE(lost_entities.find(entity_3) != lost_entities.end()); -} - -TEST(LostEntityTrackerTest, SomeEntitiesLost) { - LostEntityTracker lost_entity_tracker; - TestEntity entity_1{1}; - TestEntity entity_2{2}; - TestEntity entity_3{3}; - - // Discover some entities. - lost_entity_tracker.RecordFoundEntity(entity_1); - lost_entity_tracker.RecordFoundEntity(entity_2); - - // Make sure none are lost on the first round. - EXPECT_TRUE(lost_entity_tracker.ComputeLostEntities().empty()); - - // Go through the next round only rediscovering one of our entities and - // discovering an additional entity as well. Then, verify that only one entity - // was lost after the check. - lost_entity_tracker.RecordFoundEntity(entity_1); - lost_entity_tracker.RecordFoundEntity(entity_3); - typename LostEntityTracker::EntitySet lost_entities = - lost_entity_tracker.ComputeLostEntities(); - EXPECT_TRUE(lost_entities.find(entity_1) == lost_entities.end()); - EXPECT_TRUE(lost_entities.find(entity_2) != lost_entities.end()); - EXPECT_TRUE(lost_entities.find(entity_3) == lost_entities.end()); -} - -TEST(LostEntityTrackerTest, SameEntityMultipleCopies) { - LostEntityTracker lost_entity_tracker; - TestEntity entity_1{1}; - TestEntity entity_1_copy{1}; - - // Discover an entity. - lost_entity_tracker.RecordFoundEntity(entity_1); - - // Make sure none are lost on the first round. - EXPECT_TRUE(lost_entity_tracker.ComputeLostEntities().empty()); - - // Rediscover the same entity, but through a copy of it. - lost_entity_tracker.RecordFoundEntity(entity_1_copy); - - // Make sure none are lost on the second round. - EXPECT_TRUE(lost_entity_tracker.ComputeLostEntities().empty()); - - // Go through a round without rediscovering any entities and verify that we - // lost an entity equivalent to both copies of it. - typename LostEntityTracker::EntitySet lost_entities = - lost_entity_tracker.ComputeLostEntities(); - EXPECT_EQ(lost_entities.size(), 1); - EXPECT_TRUE(lost_entities.find(entity_1) != lost_entities.end()); - EXPECT_TRUE(lost_entities.find(entity_1_copy) != lost_entities.end()); -} - -} // namespace -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/mediums/mediums.cc b/cpp/core_v2/internal/mediums/mediums.cc deleted file mode 100644 index 2a9c58b2..00000000 --- a/cpp/core_v2/internal/mediums/mediums.cc +++ /dev/null @@ -1,25 +0,0 @@ -#include "core_v2/internal/mediums/mediums.h" - -namespace location { -namespace nearby { -namespace connections { - -BluetoothRadio& Mediums::GetBluetoothRadio() { - return bluetooth_radio_; -} - -BluetoothClassic& Mediums::GetBluetoothClassic() { - return bluetooth_classic_; -} - -Ble& Mediums::GetBle() { return ble_; } - -WifiLan& Mediums::GetWifiLan() { - return wifi_lan_; -} - -mediums::WebRtc& Mediums::GetWebRtc() { return webrtc_; } - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/mediums/mediums.h b/cpp/core_v2/internal/mediums/mediums.h deleted file mode 100644 index 367365ea..00000000 --- a/cpp/core_v2/internal/mediums/mediums.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_MEDIUMS_H_ -#define CORE_V2_INTERNAL_MEDIUMS_MEDIUMS_H_ - -#include "core_v2/internal/mediums/ble.h" -#include "core_v2/internal/mediums/bluetooth_classic.h" -#include "core_v2/internal/mediums/bluetooth_radio.h" -#include "core_v2/internal/mediums/webrtc.h" -#include "core_v2/internal/mediums/wifi_lan.h" - -namespace location { -namespace nearby { -namespace connections { - -// Facilitates convenient and reliable usage of various wireless mediums. -class Mediums { - public: - Mediums() = default; - ~Mediums() = default; - - // Returns a handle to the Bluetooth radio. - BluetoothRadio& GetBluetoothRadio(); - - // Returns a handle to the Bluetooth Classic medium. - BluetoothClassic& GetBluetoothClassic(); - - // Returns a handle to the Ble medium. - Ble& GetBle(); - - // Returns a handle to the Wifi-Lan medium. - WifiLan& GetWifiLan(); - - // Returns a handle to the WebRtc medium. - mediums::WebRtc& GetWebRtc(); - - private: - // The order of declaration is critical for both construction and - // destruction. - // - // 1) Construction: The individual mediums have a dependency on the - // corresponding radio, so the radio must be initialized first. - // - // 2) Destruction: The individual mediums should be shut down before the - // corresponding radio. - BluetoothRadio bluetooth_radio_; - BluetoothClassic bluetooth_classic_{bluetooth_radio_}; - Ble ble_{bluetooth_radio_}; - WifiLan wifi_lan_; - mediums::WebRtc webrtc_; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_MEDIUMS_MEDIUMS_H_ diff --git a/cpp/core_v2/internal/mediums/utils.cc b/cpp/core_v2/internal/mediums/utils.cc deleted file mode 100644 index 289c13a6..00000000 --- a/cpp/core_v2/internal/mediums/utils.cc +++ /dev/null @@ -1,65 +0,0 @@ -#include "core_v2/internal/mediums/utils.h" - -#include -#include - -#include "platform_v2/base/prng.h" -#include "platform_v2/public/crypto.h" - -namespace location { -namespace nearby { -namespace connections { - -namespace { -constexpr absl::string_view kUpgradeServiceIdPostfix = "_UPGRADE"; -} - -ByteArray Utils::GenerateRandomBytes(size_t length) { - Prng rng; - std::string data; - data.reserve(length); - - // Adds 4 random bytes per iteration. - while (length > 0) { - std::uint32_t val = rng.NextUint32(); - for (int i = 0; i < 4; i++) { - data += val & 0xFF; - val >>= 8; - length--; - - if (!length) break; - } - } - - return ByteArray(data); -} - -ByteArray Utils::Sha256Hash(const ByteArray& source, size_t length) { - return Utils::Sha256Hash(std::string(source), length); -} - -ByteArray Utils::Sha256Hash(const std::string& source, size_t length) { - ByteArray full_hash(length); - full_hash.CopyAt(0, Crypto::Sha256(source)); - return full_hash; -} - -std::string Utils::WrapUpgradeServiceId(const std::string& service_id) { - if (service_id.empty()) { - return {}; - } - return service_id + std::string(kUpgradeServiceIdPostfix); -} - -std::string Utils::UnwrapUpgradeServiceId( - const std::string& upgrade_service_id) { - auto pos = upgrade_service_id.find(std::string(kUpgradeServiceIdPostfix)); - if (pos != std::string::npos) { - return std::string(upgrade_service_id, 0, pos); - } - return upgrade_service_id; -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/mediums/utils.h b/cpp/core_v2/internal/mediums/utils.h deleted file mode 100644 index 00e93c35..00000000 --- a/cpp/core_v2/internal/mediums/utils.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_UTILS_H_ -#define CORE_V2_INTERNAL_MEDIUMS_UTILS_H_ - -#include - -#include "platform_v2/base/byte_array.h" - -namespace location { -namespace nearby { -namespace connections { - -class Utils { - public: - static ByteArray GenerateRandomBytes(size_t length); - static ByteArray Sha256Hash(const ByteArray& source, size_t length); - static ByteArray Sha256Hash(const std::string& source, size_t length); - static std::string WrapUpgradeServiceId(const std::string& service_id); - static std::string UnwrapUpgradeServiceId(const std::string& service_id); -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_MEDIUMS_UTILS_H_ diff --git a/cpp/core_v2/internal/mediums/uuid.cc b/cpp/core_v2/internal/mediums/uuid.cc deleted file mode 100644 index 2bd8b947..00000000 --- a/cpp/core_v2/internal/mediums/uuid.cc +++ /dev/null @@ -1,75 +0,0 @@ -#include "core_v2/internal/mediums/uuid.h" - -#include -#include - -#include "platform_v2/public/crypto.h" - -namespace location { -namespace nearby { -namespace connections { -namespace { -std::ostream& write_hex(std::ostream& os, absl::string_view data) { - for (const auto b : data) { - os << std::setfill('0') - << std::setw(2) - << std::hex - << (static_cast(b) & 0x0ff); - } - return os; -} -} // namespace - -Uuid::Uuid(absl::string_view data) : data_(Crypto::Md5(data)) { - // Based on the Java counterpart at - // http://androidxref.com/8.0.0_r4/xref/libcore/ojluni/src/main/java/java/util/UUID.java#162. - data_[6] &= 0x0f; // Clear version. - data_[6] |= 0x30; // Set to version 3. - data_[8] &= 0x3f; // Clear variant. - data_[8] |= 0x80; // Set to IETF variant. -} - -Uuid::Uuid(std::uint64_t most_sig_bits, std::uint64_t least_sig_bits) { - // Base on the Java counterpart at - // http://androidxref.com/8.0.0_r4/xref/libcore/ojluni/src/main/java/java/util/UUID.java#104. - data_.reserve(sizeof(most_sig_bits) + sizeof(least_sig_bits)); - - data_[0] = static_cast((most_sig_bits >> 56) & 0x0ff); - data_[1] = static_cast((most_sig_bits >> 48) & 0x0ff); - data_[2] = static_cast((most_sig_bits >> 40) & 0x0ff); - data_[3] = static_cast((most_sig_bits >> 32) & 0x0ff); - data_[4] = static_cast((most_sig_bits >> 24) & 0x0ff); - data_[5] = static_cast((most_sig_bits >> 16) & 0x0ff); - data_[6] = static_cast((most_sig_bits >> 8) & 0x0ff); - data_[7] = static_cast((most_sig_bits >> 0) & 0x0ff); - - data_[8] = static_cast((least_sig_bits >> 56) & 0x0ff); - data_[9] = static_cast((least_sig_bits >> 48) & 0x0ff); - data_[10] = static_cast((least_sig_bits >> 40) & 0x0ff); - data_[11] = static_cast((least_sig_bits >> 32) & 0x0ff); - data_[12] = static_cast((least_sig_bits >> 24) & 0x0ff); - data_[13] = static_cast((least_sig_bits >> 16) & 0x0ff); - data_[14] = static_cast((least_sig_bits >> 8) & 0x0ff); - data_[15] = static_cast((least_sig_bits >> 0) & 0x0ff); -} - -Uuid::operator std::string() const { - // Based on the Java counterpart at - // http://androidxref.com/8.0.0_r4/xref/libcore/ojluni/src/main/java/java/util/UUID.java#375. - std::ostringstream md5_hex; - write_hex(md5_hex, absl::string_view(&data_[0], 4)); - md5_hex << "-"; - write_hex(md5_hex, absl::string_view(&data_[4], 2)); - md5_hex << "-"; - write_hex(md5_hex, absl::string_view(&data_[6], 2)); - md5_hex << "-"; - write_hex(md5_hex, absl::string_view(&data_[8], 2)); - md5_hex << "-"; - write_hex(md5_hex, absl::string_view(&data_[10], 6)); - - return md5_hex.str(); -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/mediums/uuid.h b/cpp/core_v2/internal/mediums/uuid.h deleted file mode 100644 index e197ff69..00000000 --- a/cpp/core_v2/internal/mediums/uuid.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_UUID_H_ -#define CORE_V2_INTERNAL_MEDIUMS_UUID_H_ - -#include -#include - -#include "absl/strings/string_view.h" - -namespace location { -namespace nearby { -namespace connections { - -// A type 3 name-based -// (https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions_3_and_5_(namespace_name-based)) -// UUID. -// -// https://developer.android.com/reference/java/util/UUID.html -class Uuid final { - public: - Uuid() : Uuid("uuid") {} - explicit Uuid(absl::string_view data); - Uuid(std::uint64_t most_sig_bits, std::uint64_t least_sig_bits); - Uuid(const Uuid&) = default; - Uuid& operator=(const Uuid&) = default; - Uuid(Uuid&&) = default; - Uuid& operator=(Uuid&&) = default; - ~Uuid() = default; - - // Returns the canonical textual representation - // (https://en.wikipedia.org/wiki/Universally_unique_identifier#Format) of the - // UUID. - explicit operator std::string() const; - std::string data() const { - return data_; - } - - private: - std::string data_; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_MEDIUMS_UUID_H_ diff --git a/cpp/core_v2/internal/mediums/webrtc/BUILD b/cpp/core_v2/internal/mediums/webrtc/BUILD deleted file mode 100644 index b2b278b8..00000000 --- a/cpp/core_v2/internal/mediums/webrtc/BUILD +++ /dev/null @@ -1,63 +0,0 @@ -cc_library( - name = "webrtc", - srcs = [ - "connection_flow.cc", - "data_channel_observer_impl.cc", - "peer_connection_observer_impl.cc", - "peer_id.cc", - "signaling_frames.cc", - "webrtc_socket.cc", - ], - hdrs = [ - "connection_flow.h", - "data_channel_listener.h", - "data_channel_observer_impl.h", - "local_ice_candidate_listener.h", - "peer_connection_observer_impl.h", - "peer_id.h", - "session_description_wrapper.h", - "signaling_frames.h", - "webrtc_socket.h", - "webrtc_socket_wrapper.h", - ], - visibility = [ - "//core_v2/internal:__subpackages__", - ], - deps = [ - "//core_v2:core_types", - "//core_v2/internal/mediums:utils", - "//platform_v2/base", - "//platform_v2/public:comm", - "//platform_v2/public:logging", - "//platform_v2/public:types", - "//location/nearby/mediums/proto:web_rtc_signaling_frames_cc_proto", - "//absl/memory", - "//absl/strings", - "//absl/time", - "//webrtc/api:libjingle_peerconnection_api", - ], -) - -cc_test( - name = "webrtc_test", - srcs = [ - "connection_flow_test.cc", - "peer_id_test.cc", - "signaling_frames_test.cc", - "webrtc_socket_test.cc", - ], - deps = [ - ":webrtc", - "//platform_v2/base", - "//platform_v2/base:test_util", - "//platform_v2/impl/g3", # buildcleaner: keep - "//platform_v2/public:comm", - "//platform_v2/public:types", - "//net/proto2/public:proto2", - "//testing/base/public:gunit_main", - "//absl/time", - "//webrtc/api:libjingle_peerconnection_api", - "//webrtc/api:rtc_error", - "//webrtc/api:scoped_refptr", - ], -) diff --git a/cpp/core_v2/internal/mediums/webrtc/peer_id.cc b/cpp/core_v2/internal/mediums/webrtc/peer_id.cc deleted file mode 100644 index 17523381..00000000 --- a/cpp/core_v2/internal/mediums/webrtc/peer_id.cc +++ /dev/null @@ -1,40 +0,0 @@ -#include "core_v2/internal/mediums/webrtc/peer_id.h" - -#include - -#include "core_v2/internal/mediums/utils.h" -#include "absl/strings/ascii.h" -#include "absl/strings/escaping.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -namespace { -constexpr int kPeerIdLength = 64; - -std::string BytesToStringUppercase(const ByteArray& bytes) { - std::string hex_string( - absl::BytesToHexString(std::string(bytes.data(), bytes.size()))); - absl::AsciiStrToUpper(&hex_string); - return hex_string; -} -} // namespace - -PeerId PeerId::FromRandom() { - return FromSeed(Utils::GenerateRandomBytes(kPeerIdLength)); -} - -PeerId PeerId::FromSeed(const ByteArray& seed) { - ByteArray full_hash(Utils::Sha256Hash(seed, kPeerIdLength)); - ByteArray hashed_seed(full_hash.data(), kPeerIdLength / 2); - return PeerId(BytesToStringUppercase(hashed_seed)); -} - -bool PeerId::IsValid() const { return !id_.empty(); } - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/mediums/webrtc/peer_id.h b/cpp/core_v2/internal/mediums/webrtc/peer_id.h deleted file mode 100644 index 5f849d8d..00000000 --- a/cpp/core_v2/internal/mediums/webrtc/peer_id.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_WEBRTC_PEER_ID_H_ -#define CORE_V2_INTERNAL_MEDIUMS_WEBRTC_PEER_ID_H_ - -#include -#include - -#include "platform_v2/base/byte_array.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -// PeerId is used as an identifier to exchange SDP messages to establish WebRTC -// p2p connection. An empty PeerId is considered to be invalid. -class PeerId { - public: - PeerId() = default; - explicit PeerId(const std::string& id) : id_(id) {} - ~PeerId() = default; - - static PeerId FromRandom(); - static PeerId FromSeed(const ByteArray& seed); - - bool IsValid() const; - - const std::string& GetId() const { return id_; } - - private: - std::string id_; -}; - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_MEDIUMS_WEBRTC_PEER_ID_H_ diff --git a/cpp/core_v2/internal/mediums/webrtc/peer_id_test.cc b/cpp/core_v2/internal/mediums/webrtc/peer_id_test.cc deleted file mode 100644 index 37b54d04..00000000 --- a/cpp/core_v2/internal/mediums/webrtc/peer_id_test.cc +++ /dev/null @@ -1,42 +0,0 @@ -#include "core_v2/internal/mediums/webrtc/peer_id.h" - -#include - -#include "platform_v2/base/byte_array.h" -#include "platform_v2/public/crypto.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -TEST(PeerIdTest, GenerateRandomPeerId) { - PeerId peer_id = PeerId::FromRandom(); - EXPECT_EQ(64, peer_id.GetId().size()); -} - -TEST(PeerIdTest, GenerateFromSeed) { - // Values calculated by running actual SHA-256 hash on |seed|. - std::string seed = "seed"; - std::string expected_peer_id = - "19B25856E1C150CA834CFFC8B59B23ADBD0EC0389E58EB22B3B64768098D002B"; - - ByteArray seed_bytes(seed); - PeerId peer_id = PeerId::FromSeed(seed_bytes); - - EXPECT_EQ(64, peer_id.GetId().size()); - EXPECT_EQ(expected_peer_id, peer_id.GetId()); -} - -TEST(PeerIdTest, GetId) { - const std::string id = "this_is_a_test"; - PeerId peer_id(id); - EXPECT_EQ(id, peer_id.GetId()); -} - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/mediums/webrtc/signaling_frames.cc b/cpp/core_v2/internal/mediums/webrtc/signaling_frames.cc deleted file mode 100644 index 7bb7872b..00000000 --- a/cpp/core_v2/internal/mediums/webrtc/signaling_frames.cc +++ /dev/null @@ -1,120 +0,0 @@ -#include "core_v2/internal/mediums/webrtc/signaling_frames.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { -namespace webrtc_frames { -using WebRtcSignalingFrame = location::nearby::mediums::WebRtcSignalingFrame; - -namespace { - -ByteArray FrameToByteArray(const WebRtcSignalingFrame& signaling_frame) { - std::string message; - signaling_frame.SerializeToString(&message); - return ByteArray(message.c_str(), message.size()); -} - -void SetSenderId(const PeerId& sender_id, WebRtcSignalingFrame& frame) { - frame.mutable_sender_id()->set_id(sender_id.GetId()); -} - -std::unique_ptr DecodeIceCandidate( - location::nearby::mediums::IceCandidate ice_candidate_proto) { - webrtc::SdpParseError error; - return std::unique_ptr( - webrtc::CreateIceCandidate(ice_candidate_proto.sdp_mid(), - ice_candidate_proto.sdp_m_line_index(), - ice_candidate_proto.sdp(), &error)); -} - -} // namespace - -ByteArray EncodeReadyForSignalingPoke(const PeerId& sender_id) { - WebRtcSignalingFrame signaling_frame; - signaling_frame.set_type(WebRtcSignalingFrame::READY_FOR_SIGNALING_POKE_TYPE); - SetSenderId(sender_id, signaling_frame); - signaling_frame.set_allocated_ready_for_signaling_poke( - new location::nearby::mediums::ReadyForSignalingPoke()); - return FrameToByteArray(std::move(signaling_frame)); -} - -ByteArray EncodeOffer(const PeerId& sender_id, - const webrtc::SessionDescriptionInterface& offer) { - WebRtcSignalingFrame signaling_frame; - signaling_frame.set_type(WebRtcSignalingFrame::OFFER_TYPE); - SetSenderId(sender_id, signaling_frame); - std::string offer_str; - offer.ToString(&offer_str); - signaling_frame.mutable_offer() - ->mutable_session_description() - ->set_description(offer_str); - return FrameToByteArray(std::move(signaling_frame)); -} - -ByteArray EncodeAnswer(const PeerId& sender_id, - const webrtc::SessionDescriptionInterface& answer) { - WebRtcSignalingFrame signaling_frame; - signaling_frame.set_type(WebRtcSignalingFrame::ANSWER_TYPE); - SetSenderId(sender_id, signaling_frame); - std::string answer_str; - answer.ToString(&answer_str); - signaling_frame.mutable_answer() - ->mutable_session_description() - ->set_description(answer_str); - return FrameToByteArray(std::move(signaling_frame)); -} - -ByteArray EncodeIceCandidates( - const PeerId& sender_id, - const std::vector& - ice_candidates) { - WebRtcSignalingFrame signaling_frame; - signaling_frame.set_type(WebRtcSignalingFrame::ICE_CANDIDATES_TYPE); - SetSenderId(sender_id, signaling_frame); - for (const auto& ice_candidate : ice_candidates) { - *signaling_frame.mutable_ice_candidates()->add_ice_candidates() = - ice_candidate; - } - return FrameToByteArray(std::move(signaling_frame)); -} - -std::unique_ptr DecodeOffer( - const WebRtcSignalingFrame& frame) { - return webrtc::CreateSessionDescription( - webrtc::SdpType::kOffer, - frame.offer().session_description().description()); -} - -std::unique_ptr DecodeAnswer( - const WebRtcSignalingFrame& frame) { - return webrtc::CreateSessionDescription( - webrtc::SdpType::kAnswer, - frame.answer().session_description().description()); -} - -std::vector> DecodeIceCandidates( - const WebRtcSignalingFrame& frame) { - std::vector> ice_candidates; - for (const auto& candidate : frame.ice_candidates().ice_candidates()) { - ice_candidates.push_back(DecodeIceCandidate(candidate)); - } - return ice_candidates; -} - -location::nearby::mediums::IceCandidate EncodeIceCandidate( - const webrtc::IceCandidateInterface& ice_candidate) { - std::string sdp; - ice_candidate.ToString(&sdp); - location::nearby::mediums::IceCandidate ice_candidate_proto; - ice_candidate_proto.set_sdp(sdp); - ice_candidate_proto.set_sdp_mid(ice_candidate.sdp_mid()); - ice_candidate_proto.set_sdp_m_line_index(ice_candidate.sdp_mline_index()); - return ice_candidate_proto; -} - -} // namespace webrtc_frames -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/mediums/webrtc/signaling_frames.h b/cpp/core_v2/internal/mediums/webrtc/signaling_frames.h deleted file mode 100644 index 78fe328a..00000000 --- a/cpp/core_v2/internal/mediums/webrtc/signaling_frames.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_WEBRTC_SIGNALING_FRAMES_H_ -#define CORE_V2_INTERNAL_MEDIUMS_WEBRTC_SIGNALING_FRAMES_H_ - -#include - -#include "core_v2/internal/mediums/webrtc/peer_id.h" -#include "platform_v2/base/byte_array.h" -#include "location/nearby/mediums/proto/web_rtc_signaling_frames.pb.h" -#include "webrtc/api/peer_connection_interface.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { -namespace webrtc_frames { - -ByteArray EncodeReadyForSignalingPoke(const PeerId& sender_id); - -ByteArray EncodeOffer(const PeerId& sender_id, - const webrtc::SessionDescriptionInterface& offer); -ByteArray EncodeAnswer(const PeerId& sender_id, - const webrtc::SessionDescriptionInterface& answer); - -ByteArray EncodeIceCandidates( - const PeerId& sender_id, - const std::vector& ice_candidates); -location::nearby::mediums::IceCandidate EncodeIceCandidate( - const webrtc::IceCandidateInterface& ice_candidate); - -std::unique_ptr DecodeOffer( - const location::nearby::mediums::WebRtcSignalingFrame& frame); -std::unique_ptr DecodeAnswer( - const location::nearby::mediums::WebRtcSignalingFrame& frame); - -std::vector> DecodeIceCandidates( - const location::nearby::mediums::WebRtcSignalingFrame& frame); - -} // namespace webrtc_frames -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_MEDIUMS_WEBRTC_SIGNALING_FRAMES_H_ diff --git a/cpp/core_v2/internal/mediums/webrtc/signaling_frames_test.cc b/cpp/core_v2/internal/mediums/webrtc/signaling_frames_test.cc deleted file mode 100644 index 54ecd527..00000000 --- a/cpp/core_v2/internal/mediums/webrtc/signaling_frames_test.cc +++ /dev/null @@ -1,182 +0,0 @@ -#include "core_v2/internal/mediums/webrtc/signaling_frames.h" - -#include - -#include "core_v2/internal/mediums/webrtc/peer_id.h" -#include "net/proto2/public/text_format.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { -namespace webrtc_frames { - -namespace { - -const char kSampleSdp[] = - "v=0\r\no=- 7859371131 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 " - "0\r\na=msid-semantic: WMS\r\n"; - -const char kIceCandidateSdp1[] = - "a=candidate:1 1 UDP 2130706431 10.0.1.1 8998 typ host"; -const char kIceCandidateSdp2[] = - "a=candidate:2 1 UDP 1694498815 192.0.2.3 45664 typ srflx raddr"; - -const char kIceSdpMid[] = "data"; -const int kIceSdpMLineIndex = 0; - -const char kOfferProto[] = R"( - sender_id { id: "abc" } - type: OFFER_TYPE - offer { - session_description { - description: "v=0\r\no=- 7859371131 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS\r\n" - } - } - )"; - -const char kAnswerProto[] = R"( - sender_id { id: "abc" } - type: ANSWER_TYPE - answer { - session_description { - description: "v=0\r\no=- 7859371131 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS\r\n" - } - } - )"; - -const char kIceCandidatesProto[] = R"( - sender_id { id: "abc" } - type: ICE_CANDIDATES_TYPE - ice_candidates { - ice_candidates { - sdp: "candidate:1 1 udp 2130706431 10.0.1.1 8998 typ host generation 0" - sdp_mid: "data" - sdp_m_line_index: 0 - } - ice_candidates { - sdp: "candidate:2 1 udp 1694498815 192.0.2.3 45664 typ srflx generation 0" - sdp_mid: "data" - sdp_m_line_index: 0 - } - } - )"; -} // namespace - -TEST(SignalingFramesTest, SignalingPoke) { - PeerId sender_id("abc"); - ByteArray encoded_poke = EncodeReadyForSignalingPoke(sender_id); - - location::nearby::mediums::WebRtcSignalingFrame frame; - frame.ParseFromString(std::string(encoded_poke.data(), encoded_poke.size())); - - EXPECT_THAT(frame, testing::EqualsProto(R"( - sender_id { id: "abc" } - type: READY_FOR_SIGNALING_POKE_TYPE - ready_for_signaling_poke {} - )")); -} - -TEST(SignalingFramesTest, EncodeValidOffer) { - PeerId sender_id("abc"); - std::unique_ptr offer = - webrtc::CreateSessionDescription(webrtc::SdpType::kOffer, kSampleSdp); - ByteArray encoded_offer = EncodeOffer(sender_id, *offer); - - location::nearby::mediums::WebRtcSignalingFrame frame; - frame.ParseFromString( - std::string(encoded_offer.data(), encoded_offer.size())); - - EXPECT_THAT(frame, testing::EqualsProto(kOfferProto)); -} - -TEST(SignaingFramesTest, DecodeValidOffer) { - location::nearby::mediums::WebRtcSignalingFrame frame; - proto2::TextFormat::ParseFromString(kOfferProto, &frame); - std::unique_ptr decoded_offer = - DecodeOffer(frame); - - EXPECT_EQ(webrtc::SdpType::kOffer, decoded_offer->GetType()); - std::string description; - decoded_offer->ToString(&description); - EXPECT_EQ(kSampleSdp, description); -} - -TEST(SignalingFramesTest, EncodeValidAnswer) { - PeerId sender_id("abc"); - std::unique_ptr answer( - webrtc::CreateSessionDescription(webrtc::SdpType::kAnswer, kSampleSdp)); - ByteArray encoded_answer = EncodeAnswer(sender_id, *answer); - - location::nearby::mediums::WebRtcSignalingFrame frame; - frame.ParseFromString( - std::string(encoded_answer.data(), encoded_answer.size())); - - EXPECT_THAT(frame, testing::EqualsProto(kAnswerProto)); -} - -TEST(SignalingFramesTest, DecodeValidAnswer) { - location::nearby::mediums::WebRtcSignalingFrame frame; - proto2::TextFormat::ParseFromString(kAnswerProto, &frame); - std::unique_ptr decoded_answer = - DecodeAnswer(frame); - - EXPECT_EQ(webrtc::SdpType::kAnswer, decoded_answer->GetType()); - std::string description; - decoded_answer->ToString(&description); - EXPECT_EQ(kSampleSdp, description); -} - -TEST(SignalingFramesTest, EncodeValidIceCandidates) { - PeerId sender_id("abc"); - webrtc::SdpParseError error; - - std::vector> ice_candidates; - ice_candidates.emplace_back(webrtc::CreateIceCandidate( - kIceSdpMid, kIceSdpMLineIndex, kIceCandidateSdp1, &error)); - ice_candidates.emplace_back(webrtc::CreateIceCandidate( - kIceSdpMid, kIceSdpMLineIndex, kIceCandidateSdp2, &error)); - std::vector encoded_candidates_vec; - for (const auto& ice_candidate : ice_candidates) { - encoded_candidates_vec.push_back(EncodeIceCandidate(*ice_candidate)); - } - ByteArray encoded_candidates = - EncodeIceCandidates(sender_id, encoded_candidates_vec); - - location::nearby::mediums::WebRtcSignalingFrame frame; - frame.ParseFromString( - std::string(encoded_candidates.data(), encoded_candidates.size())); - - EXPECT_THAT(frame, testing::EqualsProto(kIceCandidatesProto)); -} - -TEST(SignalingFramesTest, DecodeValidIceCandidates) { - webrtc::SdpParseError error; - std::vector> ice_candidates; - ice_candidates.emplace_back(webrtc::CreateIceCandidate( - kIceSdpMid, kIceSdpMLineIndex, kIceCandidateSdp1, &error)); - ice_candidates.emplace_back(webrtc::CreateIceCandidate( - kIceSdpMid, kIceSdpMLineIndex, kIceCandidateSdp2, &error)); - - location::nearby::mediums::WebRtcSignalingFrame frame; - proto2::TextFormat::ParseFromString(kIceCandidatesProto, &frame); - std::vector> - decoded_candidates = DecodeIceCandidates(frame); - - ASSERT_EQ(2u, decoded_candidates.size()); - for (int i = 0; i < static_cast(decoded_candidates.size()); i++) { - EXPECT_TRUE(ice_candidates[i]->candidate().IsEquivalent( - decoded_candidates[i]->candidate())); - EXPECT_EQ(ice_candidates[i]->sdp_mid(), decoded_candidates[i]->sdp_mid()); - EXPECT_EQ(ice_candidates[i]->sdp_mline_index(), - decoded_candidates[i]->sdp_mline_index()); - } -} - -} // namespace webrtc_frames -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/mediums/webrtc/webrtc_socket.cc b/cpp/core_v2/internal/mediums/webrtc/webrtc_socket.cc deleted file mode 100644 index 1caa43e3..00000000 --- a/cpp/core_v2/internal/mediums/webrtc/webrtc_socket.cc +++ /dev/null @@ -1,101 +0,0 @@ -#include "core_v2/internal/mediums/webrtc/webrtc_socket.h" - -#include "platform_v2/public/logging.h" -#include "platform_v2/public/mutex_lock.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -// OutputStreamImpl -Exception WebRtcSocket::OutputStreamImpl::Write(const ByteArray& data) { - if (data.size() > kMaxDataSize) { - NEARBY_LOG(WARNING, "Sending data larger than 1MB"); - return {Exception::kIo}; - } - - socket_->BlockUntilSufficientSpaceInBuffer(data.size()); - - if (socket_->IsClosed()) { - NEARBY_LOG(WARNING, "Tried sending message while socket is closed"); - return {Exception::kIo}; - } - - if (!socket_->SendMessage(data)) { - return {Exception::kIo}; - } - return {Exception::kSuccess}; -} - -Exception WebRtcSocket::OutputStreamImpl::Flush() { - // Java implementation is empty. - return {Exception::kSuccess}; -} - -Exception WebRtcSocket::OutputStreamImpl::Close() { - socket_->Close(); - return {Exception::kSuccess}; -} - -// WebRtcSocket -WebRtcSocket::WebRtcSocket( - const std::string& name, - rtc::scoped_refptr data_channel) - : name_(name), data_channel_(std::move(data_channel)) {} - -InputStream& WebRtcSocket::GetInputStream() { return pipe_.GetInputStream(); } - -OutputStream& WebRtcSocket::GetOutputStream() { return output_stream_; } - -void WebRtcSocket::Close() { - if (IsClosed()) return; - - closed_.Set(true); - pipe_.GetInputStream().Close(); - pipe_.GetOutputStream().Close(); - data_channel_->Close(); - WakeUpWriter(); - socket_closed_listener_.socket_closed_cb(); -} - -void WebRtcSocket::NotifyDataChannelMsgReceived(const ByteArray& message) { - if (!pipe_.GetOutputStream().Write(message).Ok()) { - Close(); - return; - } - - if (!pipe_.GetOutputStream().Flush().Ok()) Close(); -} - -void WebRtcSocket::NotifyDataChannelBufferedAmountChanged() { WakeUpWriter(); } - -bool WebRtcSocket::SendMessage(const ByteArray& data) { - return data_channel_->Send( - webrtc::DataBuffer(std::string(data.data(), data.size()))); -} - -bool WebRtcSocket::IsClosed() { return closed_.Get(); } - -void WebRtcSocket::WakeUpWriter() { - MutexLock lock(&backpressure_mutex_); - buffer_variable_.Notify(); -} - -void WebRtcSocket::SetOnSocketClosedListener(SocketClosedListener&& listener) { - socket_closed_listener_ = std::move(listener); -} - -void WebRtcSocket::BlockUntilSufficientSpaceInBuffer(int length) { - MutexLock lock(&backpressure_mutex_); - while (!IsClosed() && - (data_channel_->buffered_amount() + length > kMaxDataSize)) { - // TODO(himanshujaju): Add wait with timeout. - buffer_variable_.Wait(); - } -} - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/mediums/webrtc/webrtc_socket.h b/cpp/core_v2/internal/mediums/webrtc/webrtc_socket.h deleted file mode 100644 index c416901e..00000000 --- a/cpp/core_v2/internal/mediums/webrtc/webrtc_socket.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_H_ -#define CORE_V2_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_H_ - -#include - -#include "core_v2/listeners.h" -#include "platform_v2/base/input_stream.h" -#include "platform_v2/base/output_stream.h" -#include "platform_v2/base/socket.h" -#include "platform_v2/public/atomic_boolean.h" -#include "platform_v2/public/condition_variable.h" -#include "platform_v2/public/mutex.h" -#include "platform_v2/public/pipe.h" -#include "webrtc/api/data_channel_interface.h" -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -// Maximum data size: 1 MB -constexpr int kMaxDataSize = 1 * 1024 * 1024; - -// Defines the Socket implementation specific to WebRTC, which uses the WebRTC -// data channel to send and receive messages. -// -// Messages are buffered here to prevent the data channel from overflowing, -// which could lead to data loss. -class WebRtcSocket : public Socket { - public: - WebRtcSocket(const std::string& name, - rtc::scoped_refptr data_channel); - ~WebRtcSocket() override = default; - - WebRtcSocket(const WebRtcSocket& other) = delete; - WebRtcSocket& operator=(const WebRtcSocket& other) = delete; - - // Overrides for location::nearby::Socket: - InputStream& GetInputStream() override; - OutputStream& GetOutputStream() override; - void Close() override; - - // Callback from WebRTC data channel when new message has been received from - // the remote. - void NotifyDataChannelMsgReceived(const ByteArray& message); - - // Callback from WebRTC data channel that the buffered data amount has - // changed. - void NotifyDataChannelBufferedAmountChanged(); - - // Listener class the gets called when the socket is closed. - struct SocketClosedListener { - std::function socket_closed_cb = DefaultCallback<>(); - }; - - void SetOnSocketClosedListener(SocketClosedListener&& listener); - - private: - class OutputStreamImpl : public OutputStream { - public: - explicit OutputStreamImpl(WebRtcSocket* const socket) : socket_(socket) {} - ~OutputStreamImpl() override = default; - - OutputStreamImpl(const OutputStreamImpl& other) = delete; - OutputStreamImpl& operator=(const OutputStreamImpl& other) = delete; - - // OutputStream: - Exception Write(const ByteArray& data) override; - Exception Flush() override; - Exception Close() override; - - private: - // |this| OutputStreamImpl is owned by |socket_|. - WebRtcSocket* const socket_; - }; - - void WakeUpWriter(); - bool IsClosed(); - bool SendMessage(const ByteArray& data); - void BlockUntilSufficientSpaceInBuffer(int length); - - std::string name_; - rtc::scoped_refptr data_channel_; - - Pipe pipe_; - - OutputStreamImpl output_stream_{this}; - - AtomicBoolean closed_{false}; - - SocketClosedListener socket_closed_listener_; - - mutable Mutex backpressure_mutex_; - ConditionVariable buffer_variable_{&backpressure_mutex_}; -}; - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_H_ diff --git a/cpp/core_v2/internal/mediums/webrtc/webrtc_socket_test.cc b/cpp/core_v2/internal/mediums/webrtc/webrtc_socket_test.cc deleted file mode 100644 index 423b06ed..00000000 --- a/cpp/core_v2/internal/mediums/webrtc/webrtc_socket_test.cc +++ /dev/null @@ -1,154 +0,0 @@ -#include "core_v2/internal/mediums/webrtc/webrtc_socket.h" - -#include - -#include "platform_v2/base/byte_array.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "webrtc/api/data_channel_interface.h" - -namespace location { -namespace nearby { -namespace connections { -namespace mediums { - -namespace { - -// using TestPlatform = platform::ImplementationPlatform; - -const char kSocketName[] = "TestSocket"; - -class MockDataChannel - : public rtc::RefCountedObject { - public: - MOCK_METHOD(void, RegisterObserver, (webrtc::DataChannelObserver*)); - MOCK_METHOD(void, UnregisterObserver, ()); - - MOCK_METHOD(std::string, label, (), (const)); - - MOCK_METHOD(bool, reliable, (), (const)); - MOCK_METHOD(int, id, (), (const)); - MOCK_METHOD(DataState, state, (), (const)); - MOCK_METHOD(uint32_t, messages_sent, (), (const)); - MOCK_METHOD(uint64_t, bytes_sent, (), (const)); - MOCK_METHOD(uint32_t, messages_received, (), (const)); - MOCK_METHOD(uint64_t, bytes_received, (), (const)); - - MOCK_METHOD(uint64_t, buffered_amount, (), (const)); - - MOCK_METHOD(void, Close, ()); - - MOCK_METHOD(bool, Send, (const webrtc::DataBuffer&)); -}; - -} // namespace - -TEST(WebRtcSocketTest, ReadFromSocket) { - const ByteArray kMessage{"Message"}; - rtc::scoped_refptr mock_data_channel = new MockDataChannel(); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - - webrtc_socket.NotifyDataChannelMsgReceived(kMessage); - ExceptionOr result = webrtc_socket.GetInputStream().Read(7); - EXPECT_TRUE(result.ok()); - EXPECT_EQ(result.result(), kMessage); -} - -TEST(WebRtcSocketTest, ReadMultipleMessages) { - rtc::scoped_refptr mock_data_channel = new MockDataChannel(); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - - webrtc_socket.NotifyDataChannelMsgReceived(ByteArray{"Me"}); - webrtc_socket.NotifyDataChannelMsgReceived(ByteArray{"ssa"}); - webrtc_socket.NotifyDataChannelMsgReceived(ByteArray{"ge"}); - - ExceptionOr result; - - // This behaviour is different from the Java code - result = webrtc_socket.GetInputStream().Read(7); - EXPECT_TRUE(result.ok()); - EXPECT_EQ(result.result(), ByteArray{"Me"}); - - result = webrtc_socket.GetInputStream().Read(7); - EXPECT_TRUE(result.ok()); - EXPECT_EQ(result.result(), ByteArray{"ssa"}); - - result = webrtc_socket.GetInputStream().Read(7); - EXPECT_TRUE(result.ok()); - EXPECT_EQ(result.result(), ByteArray{"ge"}); -} - -TEST(WebRtcSocketTest, WriteToSocket) { - const ByteArray kMessage{"Message"}; - rtc::scoped_refptr mock_data_channel = new MockDataChannel(); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - - EXPECT_CALL(*mock_data_channel, Send(testing::_)) - .WillRepeatedly(testing::Return(true)); - EXPECT_TRUE(webrtc_socket.GetOutputStream().Write(kMessage).Ok()); -} - -TEST(WebRtcSocketTest, SendDataBiggerThanMax) { - const ByteArray kMessage{kMaxDataSize + 1}; - rtc::scoped_refptr mock_data_channel = new MockDataChannel(); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - - EXPECT_CALL(*mock_data_channel, Send(testing::_)).Times(0); - EXPECT_EQ(webrtc_socket.GetOutputStream().Write(kMessage), - Exception{Exception::kIo}); -} - -TEST(WebRtcSocketTest, WriteToDataChannelFails) { - ByteArray kMessage{"Message"}; - rtc::scoped_refptr mock_data_channel = new MockDataChannel(); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - - ON_CALL(*mock_data_channel, Send(testing::_)) - .WillByDefault(testing::Return(false)); - EXPECT_EQ(webrtc_socket.GetOutputStream().Write(kMessage), - Exception{Exception::kIo}); -} - -TEST(WebRtcSocketTest, Close) { - rtc::scoped_refptr mock_data_channel = new MockDataChannel(); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - - EXPECT_CALL(*mock_data_channel, Close()); - - int socket_closed_cb_called = 0; - - webrtc_socket.SetOnSocketClosedListener( - {.socket_closed_cb = [&]() { socket_closed_cb_called++; }}); - webrtc_socket.Close(); - - EXPECT_EQ(socket_closed_cb_called, 1); -} - -TEST(WebRtcSocketTest, WriteOnClosedChannel) { - ByteArray kMessage{"Message"}; - rtc::scoped_refptr mock_data_channel = new MockDataChannel(); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - webrtc_socket.Close(); - - EXPECT_CALL(*mock_data_channel, Send(testing::_)).Times(0); - EXPECT_EQ(webrtc_socket.GetOutputStream().Write(kMessage), - Exception{Exception::kIo}); -} - -TEST(WebRtcSocketTest, ReadFromClosedChannel) { - ByteArray kMessage{"Message"}; - rtc::scoped_refptr mock_data_channel = new MockDataChannel(); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - ON_CALL(*mock_data_channel, Send(testing::_)) - .WillByDefault(testing::Return(true)); - - webrtc_socket.GetOutputStream().Write(kMessage); - webrtc_socket.Close(); - - EXPECT_EQ(webrtc_socket.GetInputStream().Read(7).exception(), Exception::kIo); -} - -} // namespace mediums -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/mediums/wifi_lan.cc b/cpp/core_v2/internal/mediums/wifi_lan.cc deleted file mode 100644 index 531b3941..00000000 --- a/cpp/core_v2/internal/mediums/wifi_lan.cc +++ /dev/null @@ -1,246 +0,0 @@ -#include "core_v2/internal/mediums/wifi_lan.h" - -#include -#include -#include - -#include "platform_v2/public/logging.h" -#include "platform_v2/public/mutex_lock.h" - -namespace location { -namespace nearby { -namespace connections { - -bool WifiLan::IsAvailable() const { - MutexLock lock(&mutex_); - - return IsAvailableLocked(); -} - -bool WifiLan::IsAvailableLocked() const { return medium_.IsValid(); } - -bool WifiLan::StartAdvertising(const std::string& service_id, - const std::string& service_info_name) { - MutexLock lock(&mutex_); - - if (service_info_name.empty()) { - NEARBY_LOG( - INFO, - "Refusing to turn on WifiLan advertising. Empty service info name."); - return false; - } - - if (!IsAvailableLocked()) { - NEARBY_LOG(INFO, - "Can't turn on WifiLan advertising. WifiLan is not available."); - return false; - } - - if (!medium_.StartAdvertising(service_id, service_info_name)) { - NEARBY_LOG( - INFO, "Failed to turn on WifiLan advertising with service info name=%s", - service_info_name.c_str()); - return false; - } - - NEARBY_LOGS(INFO) << "Turned on WifiLan advertising with service info name=" - << service_info_name << ", service id=" << service_id; - advertising_info_.Add(service_id); - return true; -} - -bool WifiLan::StopAdvertising(const std::string& service_id) { - MutexLock lock(&mutex_); - - if (!IsAdvertisingLocked(service_id)) { - NEARBY_LOG(INFO, "Can't turn off WifiLan advertising; it is already off"); - return false; - } - - NEARBY_LOG(INFO, "Turned off WifiLan advertising with service id=%s", - service_id.c_str()); - bool ret = medium_.StopAdvertising(service_id); - // Reset our bundle of advertising state to mark that we're no longer - // advertising. - advertising_info_.Remove(service_id); - return ret; -} - -bool WifiLan::IsAdvertising(const std::string& service_id) { - MutexLock lock(&mutex_); - - return IsAdvertisingLocked(service_id); -} - -bool WifiLan::IsAdvertisingLocked(const std::string& service_id) { - return advertising_info_.Existed(service_id); -} - -bool WifiLan::StartDiscovery(const std::string& service_id, - DiscoveredServiceCallback callback) { - MutexLock lock(&mutex_); - - if (service_id.empty()) { - NEARBY_LOG(INFO, - "Refusing to start WifiLan discovering with empty service id."); - return false; - } - - if (!IsAvailableLocked()) { - NEARBY_LOG( - INFO, - "Can't discover WifiLan services because WifiLan isn't available."); - return false; - } - - if (IsDiscoveringLocked(service_id)) { - NEARBY_LOG( - INFO, - "Refusing to start discovery of WifiLan services because another " - "discovery is already in-progress."); - return false; - } - - if (!medium_.StartDiscovery(service_id, callback)) { - NEARBY_LOG(INFO, "Failed to start discovery of WifiLan services."); - return false; - } - - NEARBY_LOG(INFO, "Turned on WifiLan discovering with service id=%s", - service_id.c_str()); - // Mark the fact that we're currently performing a WifiLan discovering. - discovering_info_.Add(service_id); - return true; -} - -bool WifiLan::StopDiscovery(const std::string& service_id) { - MutexLock lock(&mutex_); - - if (!IsDiscoveringLocked(service_id)) { - NEARBY_LOG(INFO, - "Can't turn off WifiLan discovering because we never started " - "discovering."); - return false; - } - - NEARBY_LOG(INFO, "Turned off WifiLan discovering with service id=%s", - service_id.c_str()); - bool ret = medium_.StopDiscovery(service_id); - discovering_info_.Clear(); - return ret; -} - -bool WifiLan::IsDiscovering(const std::string& service_id) { - MutexLock lock(&mutex_); - - return IsDiscoveringLocked(service_id); -} - -bool WifiLan::IsDiscoveringLocked(const std::string& service_id) { - return discovering_info_.Existed(service_id); -} - -bool WifiLan::StartAcceptingConnections(const std::string& service_id, - AcceptedConnectionCallback callback) { - MutexLock lock(&mutex_); - - if (service_id.empty()) { - NEARBY_LOG(INFO, - "Refusing to start accepting WifiLan connections with empty " - "service id."); - return false; - } - - if (!IsAvailableLocked()) { - NEARBY_LOG(INFO, - "Can't start accepting WifiLan connections for %s because " - "WifiLan isn't available.", - service_id.c_str()); - return false; - } - - if (IsAcceptingConnectionsLocked(service_id)) { - NEARBY_LOG(INFO, - "Refusing to start accepting WifiLan connections for %s because " - "another WifiLan service socket is already in-progress.", - service_id.c_str()); - return false; - } - - if (!medium_.StartAcceptingConnections(service_id, callback)) { - NEARBY_LOG(INFO, "Failed to accept connections callback for %s.", - service_id.c_str()); - return false; - } - - accepting_connections_info_.Add(service_id); - return true; -} - -bool WifiLan::StopAcceptingConnections(const std::string& service_id) { - MutexLock lock(&mutex_); - - if (!IsAcceptingConnectionsLocked(service_id)) { - NEARBY_LOG(INFO, - "Can't stop accepting WifiLan connections because it was never " - "started."); - return false; - } - - bool ret = medium_.StopAcceptingConnections(service_id); - // Reset our bundle of accepting connections state to mark that we're no - // longer accepting connections. - accepting_connections_info_.Remove(service_id); - return ret; -} - -bool WifiLan::IsAcceptingConnections(const std::string& service_id) { - MutexLock lock(&mutex_); - - return IsAcceptingConnectionsLocked(service_id); -} - -bool WifiLan::IsAcceptingConnectionsLocked(const std::string& service_id) { - return accepting_connections_info_.Existed(service_id); -} - -WifiLanSocket WifiLan::Connect(WifiLanService& wifi_lan_service, - const std::string& service_id) { - MutexLock lock(&mutex_); - NEARBY_LOG(INFO, "WifiLan::Connect: service=%p, service_info_name=%s", - &wifi_lan_service, wifi_lan_service.GetName().c_str()); - // Socket to return. To allow for NRVO to work, it has to be a single object. - WifiLanSocket socket; - - if (service_id.empty()) { - NEARBY_LOG(INFO, - "Refusing to create WifiLan socket with empty service_id."); - return socket; - } - - if (!IsAvailableLocked()) { - NEARBY_LOG(INFO, - "Can't create client WifiLan socket [service_id=%s]; WifiLan " - "isn't available.", - service_id.c_str()); - return socket; - } - - socket = medium_.Connect(wifi_lan_service, service_id); - if (!socket.IsValid()) { - NEARBY_LOG(INFO, "Failed to Connect via WifiLan [service_id=%s]", - service_id.c_str()); - } - - return socket; -} - -WifiLanService WifiLan::GetRemoteWifiLanService(const std::string& ip_address, - int port) { - MutexLock lock(&mutex_); - return medium_.FindRemoteService(ip_address, port); -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/mediums/wifi_lan.h b/cpp/core_v2/internal/mediums/wifi_lan.h deleted file mode 100644 index 1aeabb2d..00000000 --- a/cpp/core_v2/internal/mediums/wifi_lan.h +++ /dev/null @@ -1,144 +0,0 @@ -#ifndef CORE_V2_INTERNAL_MEDIUMS_WIFI_LAN_H_ -#define CORE_V2_INTERNAL_MEDIUMS_WIFI_LAN_H_ - -#include -#include - -#include "platform_v2/base/byte_array.h" -#include "platform_v2/public/multi_thread_executor.h" -#include "platform_v2/public/mutex.h" -#include "platform_v2/public/wifi_lan.h" -#include "absl/container/flat_hash_map.h" -#include "absl/container/flat_hash_set.h" - -namespace location { -namespace nearby { -namespace connections { - -class WifiLan { - public: - using DiscoveredServiceCallback = WifiLanMedium::DiscoveredServiceCallback; - using AcceptedConnectionCallback = WifiLanMedium::AcceptedConnectionCallback; - - // Returns true, if WifiLan communications are supported by a platform. - bool IsAvailable() const ABSL_LOCKS_EXCLUDED(mutex_); - - // Sets custom service info name, and then enables WifiLan advertising. - // Returns true, if name is successfully set, and false otherwise. - bool StartAdvertising(const std::string& service_id, - const std::string& service_info_name) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Disables WifiLan advertising, and restores service info name to - // what they were before the call to StartAdvertising(). - bool StopAdvertising(const std::string& service_id) - ABSL_LOCKS_EXCLUDED(mutex_); - - bool IsAdvertising(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_); - - // Enables WifiLan discovery mode. Will report any discoverable services in - // range through a callback. Returns true, if discovery mode was enabled, - // false otherwise. - bool StartDiscovery(const std::string& service_id, - DiscoveredServiceCallback callback) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Disables WifiLan discovery mode. - bool StopDiscovery(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_); - - bool IsDiscovering(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_); - - // Starts a worker thread, creates a WifiLan socket, associates it with a - // service id. - bool StartAcceptingConnections(const std::string& service_id, - AcceptedConnectionCallback callback) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Closes socket corresponding to a service id. - bool StopAcceptingConnections(const std::string& service_id) - ABSL_LOCKS_EXCLUDED(mutex_); - - bool IsAcceptingConnections(const std::string& service_id) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Establishes connection to WifiLan service that was might be started on - // another service with StartAcceptingConnections() using the same service_id. - // Blocks until connection is established, or server-side is terminated. - // Returns socket instance. On success, WifiLanSocket.IsValid() return true. - WifiLanSocket Connect(WifiLanService& wifi_lan_service, - const std::string& service_id) - ABSL_LOCKS_EXCLUDED(mutex_); - - WifiLanService GetRemoteWifiLanService(const std::string& ip_address, - int port) ABSL_LOCKS_EXCLUDED(mutex_); - - private: - struct AdvertisingInfo { - bool Empty() const { return service_ids.empty(); } - void Clear() { service_ids.clear(); } - void Add(const std::string& service_id) { service_ids.emplace(service_id); } - void Remove(const std::string& service_id) { - service_ids.erase(service_id); - } - bool Existed(const std::string& service_id) const { - return service_ids.contains(service_id); - } - - absl::flat_hash_set service_ids; - }; - - struct DiscoveringInfo { - bool Empty() const { return service_ids.empty(); } - void Clear() { service_ids.clear(); } - void Add(const std::string& service_id) { service_ids.emplace(service_id); } - void Remove(const std::string& service_id) { - service_ids.erase(service_id); - } - bool Existed(const std::string& service_id) const { - return service_ids.contains(service_id); - } - - absl::flat_hash_set service_ids; - }; - - struct AcceptingConnectionsInfo { - bool Empty() const { return service_ids.empty(); } - void Clear() { service_ids.clear(); } - void Add(const std::string& service_id) { service_ids.emplace(service_id); } - void Remove(const std::string& service_id) { - service_ids.erase(service_id); - } - bool Existed(const std::string& service_id) const { - return service_ids.contains(service_id); - } - - absl::flat_hash_set service_ids; - }; - - // Same as IsAvailable(), but must be called with mutex_ held. - bool IsAvailableLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Same as IsAdvertising(), but must be called with mutex_ held. - bool IsAdvertisingLocked(const std::string& service_id) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Same as IsDiscovering(), but must be called with mutex_ held. - bool IsDiscoveringLocked(const std::string& service_id) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Same as IsAcceptingConnections(), but must be called with mutex_ held. - bool IsAcceptingConnectionsLocked(const std::string& service_id) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - mutable Mutex mutex_; - WifiLanMedium medium_ ABSL_GUARDED_BY(mutex_); - AdvertisingInfo advertising_info_ ABSL_GUARDED_BY(mutex_); - DiscoveringInfo discovering_info_ ABSL_GUARDED_BY(mutex_); - AcceptingConnectionsInfo accepting_connections_info_ ABSL_GUARDED_BY(mutex_); -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_MEDIUMS_WIFI_LAN_H_ diff --git a/cpp/core_v2/internal/offline_frames.cc b/cpp/core_v2/internal/offline_frames.cc deleted file mode 100644 index fd9a6527..00000000 --- a/cpp/core_v2/internal/offline_frames.cc +++ /dev/null @@ -1,389 +0,0 @@ -#include "core_v2/internal/offline_frames.h" - -#include -#include - -#include "core/internal/message_lite.h" -#include "core_v2/status.h" -#include "proto/connections/offline_wire_formats.pb.h" -#include "platform_v2/base/byte_array.h" - -namespace location { -namespace nearby { -namespace connections { -namespace parser { -namespace { - -using ExceptionOrOfflineFrame = ExceptionOr; -using MessageLite = ::google::protobuf::MessageLite; - -ByteArray ToBytes(OfflineFrame&& frame) { - ByteArray bytes(frame.ByteSizeLong()); - frame.set_version(OfflineFrame::V1); - frame.SerializeToArray(bytes.data(), bytes.size()); - return bytes; -} - -} // namespace - -ExceptionOrOfflineFrame FromBytes(const ByteArray& bytes) { - OfflineFrame frame; - - if (frame.ParseFromString(std::string(bytes))) { - return ExceptionOrOfflineFrame(std::move(frame)); - } else { - return ExceptionOrOfflineFrame(Exception::kInvalidProtocolBuffer); - } -} - -V1Frame::FrameType GetFrameType(const OfflineFrame& frame) { - if ((frame.version() == OfflineFrame::V1) && frame.has_v1()) { - return frame.v1().type(); - } - - return V1Frame::UNKNOWN_FRAME_TYPE; -} - -ByteArray ForConnectionRequest(const std::string& endpoint_id, - const ByteArray& endpoint_info, - std::int32_t nonce, - const std::vector& mediums) { - OfflineFrame frame; - - frame.set_version(OfflineFrame::V1); - auto* v1_frame = frame.mutable_v1(); - v1_frame->set_type(V1Frame::CONNECTION_REQUEST); - auto* connection_request = v1_frame->mutable_connection_request(); - connection_request->set_endpoint_id(endpoint_id); - connection_request->set_endpoint_name(std::string(endpoint_info)); - connection_request->set_endpoint_info(std::string(endpoint_info)); - connection_request->set_nonce(nonce); - for (const auto& medium : mediums) { - connection_request->add_mediums(MediumToConnectionRequestMedium(medium)); - } - - return ToBytes(std::move(frame)); -} - -ByteArray ForConnectionResponse(std::int32_t status) { - OfflineFrame frame; - - frame.set_version(OfflineFrame::V1); - auto* v1_frame = frame.mutable_v1(); - v1_frame->set_type(V1Frame::CONNECTION_RESPONSE); - auto* sub_frame = v1_frame->mutable_connection_response(); - - // For backward compatiblility, here still sets both status and response - // parameters until the response feature is roll out in all supported - // devices. - sub_frame->set_status(status); - sub_frame->set_response(status == Status::kSuccess - ? ConnectionResponseFrame::ACCEPT - : ConnectionResponseFrame::REJECT); - - return ToBytes(std::move(frame)); -} - -ByteArray ForDataPayloadTransfer( - const PayloadTransferFrame::PayloadHeader& header, - const PayloadTransferFrame::PayloadChunk& chunk) { - OfflineFrame frame; - - frame.set_version(OfflineFrame::V1); - auto* v1_frame = frame.mutable_v1(); - v1_frame->set_type(V1Frame::PAYLOAD_TRANSFER); - auto* sub_frame = v1_frame->mutable_payload_transfer(); - sub_frame->set_packet_type(PayloadTransferFrame::DATA); - *sub_frame->mutable_payload_header() = header; - *sub_frame->mutable_payload_chunk() = chunk; - - return ToBytes(std::move(frame)); -} - -ByteArray ForControlPayloadTransfer( - const PayloadTransferFrame::PayloadHeader& header, - const PayloadTransferFrame::ControlMessage& control) { - OfflineFrame frame; - - frame.set_version(OfflineFrame::V1); - auto* v1_frame = frame.mutable_v1(); - v1_frame->set_type(V1Frame::PAYLOAD_TRANSFER); - auto* sub_frame = v1_frame->mutable_payload_transfer(); - sub_frame->set_packet_type(PayloadTransferFrame::CONTROL); - *sub_frame->mutable_payload_header() = header; - *sub_frame->mutable_control_message() = control; - - return ToBytes(std::move(frame)); -} - -ByteArray ForBwuWifiHotspotPathAvailable(const std::string& ssid, - const std::string& password, - std::int32_t port) { - OfflineFrame frame; - - frame.set_version(OfflineFrame::V1); - auto* v1_frame = frame.mutable_v1(); - v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); - auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); - sub_frame->set_event_type( - BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE); - auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info(); - upgrade_path_info->set_medium(UpgradePathInfo::WIFI_HOTSPOT); - auto* wifi_hotspot_credentials = - upgrade_path_info->mutable_wifi_hotspot_credentials(); - wifi_hotspot_credentials->set_ssid(ssid); - wifi_hotspot_credentials->set_password(password); - wifi_hotspot_credentials->set_port(port); - - return ToBytes(std::move(frame)); -} - -ByteArray ForBwuWifiLanPathAvailable(const std::string& ip_address, - std::int32_t port) { - OfflineFrame frame; - - frame.set_version(OfflineFrame::V1); - auto* v1_frame = frame.mutable_v1(); - v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); - auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); - sub_frame->set_event_type( - BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE); - auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info(); - upgrade_path_info->set_medium(UpgradePathInfo::WIFI_LAN); - auto* wifi_lan_socket = upgrade_path_info->mutable_wifi_lan_socket(); - wifi_lan_socket->set_ip_address(ip_address); - wifi_lan_socket->set_wifi_port(port); - - return ToBytes(std::move(frame)); -} - -ByteArray ForBwuBluetoothPathAvailable(const std::string& service_id, - const std::string& mac_address) { - OfflineFrame frame; - - frame.set_version(OfflineFrame::V1); - auto* v1_frame = frame.mutable_v1(); - v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); - auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); - sub_frame->set_event_type( - BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE); - auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info(); - upgrade_path_info->set_medium(UpgradePathInfo::BLUETOOTH); - auto* bluetooth_credentials = - upgrade_path_info->mutable_bluetooth_credentials(); - bluetooth_credentials->set_mac_address(mac_address); - bluetooth_credentials->set_service_name(service_id); - - return ToBytes(std::move(frame)); -} - -ByteArray ForBwuWebrtcPathAvailable(const std::string& peer_id) { - OfflineFrame frame; - - frame.set_version(OfflineFrame::V1); - auto* v1_frame = frame.mutable_v1(); - v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); - auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); - sub_frame->set_event_type( - BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE); - auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info(); - upgrade_path_info->set_medium(UpgradePathInfo::WEB_RTC); - auto* webrtc_credentials = - upgrade_path_info->mutable_web_rtc_credentials(); - webrtc_credentials->set_peer_id(peer_id); - - return ToBytes(std::move(frame)); -} - -ByteArray ForBwuLastWrite() { - OfflineFrame frame; - - frame.set_version(OfflineFrame::V1); - auto* v1_frame = frame.mutable_v1(); - v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); - auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); - sub_frame->set_event_type( - BandwidthUpgradeNegotiationFrame::LAST_WRITE_TO_PRIOR_CHANNEL); - - return ToBytes(std::move(frame)); -} - -ByteArray ForBwuSafeToClose() { - OfflineFrame frame; - - frame.set_version(OfflineFrame::V1); - auto* v1_frame = frame.mutable_v1(); - v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); - auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); - sub_frame->set_event_type( - BandwidthUpgradeNegotiationFrame::SAFE_TO_CLOSE_PRIOR_CHANNEL); - - return ToBytes(std::move(frame)); -} - -ByteArray ForBwuIntroduction(const std::string& endpoint_id) { - OfflineFrame frame; - - frame.set_version(OfflineFrame::V1); - auto* v1_frame = frame.mutable_v1(); - v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); - auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); - sub_frame->set_event_type( - BandwidthUpgradeNegotiationFrame::CLIENT_INTRODUCTION); - auto* client_introduction = sub_frame->mutable_client_introduction(); - client_introduction->set_endpoint_id(endpoint_id); - - return ToBytes(std::move(frame)); -} - -ByteArray ForBwuFailure(const UpgradePathInfo& info) { - OfflineFrame frame; - - frame.set_version(OfflineFrame::V1); - auto* v1_frame = frame.mutable_v1(); - v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); - auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); - sub_frame->set_event_type( - BandwidthUpgradeNegotiationFrame::UPGRADE_FAILURE); - auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info(); - *upgrade_path_info = info; - - return ToBytes(std::move(frame)); -} - -ByteArray ForKeepAlive() { - OfflineFrame frame; - - frame.set_version(OfflineFrame::V1); - auto* v1_frame = frame.mutable_v1(); - v1_frame->set_type(V1Frame::KEEP_ALIVE); - v1_frame->mutable_keep_alive(); - - return ToBytes(std::move(frame)); -} - -ByteArray ForDisconnection() { - OfflineFrame frame; - - frame.set_version(OfflineFrame::V1); - auto* v1_frame = frame.mutable_v1(); - v1_frame->set_type(V1Frame::DISCONNECTION); - v1_frame->mutable_disconnection(); - - return ToBytes(std::move(frame)); -} - -UpgradePathInfo::Medium MediumToUpgradePathInfoMedium(Medium medium) { - switch (medium) { - case Medium::MDNS: - return UpgradePathInfo::MDNS; - case Medium::BLUETOOTH: - return UpgradePathInfo::BLUETOOTH; - case Medium::WIFI_HOTSPOT: - return UpgradePathInfo::WIFI_HOTSPOT; - case Medium::BLE: - return UpgradePathInfo::BLE; - case Medium::WIFI_LAN: - return UpgradePathInfo::WIFI_LAN; - case Medium::WIFI_AWARE: - return UpgradePathInfo::WIFI_AWARE; - case Medium::NFC: - return UpgradePathInfo::NFC; - case Medium::WIFI_DIRECT: - return UpgradePathInfo::WIFI_DIRECT; - case Medium::WEB_RTC: - return UpgradePathInfo::WEB_RTC; - default: - return UpgradePathInfo::UNKNOWN_MEDIUM; - } -} - -Medium UpgradePathInfoMediumToMedium(UpgradePathInfo::Medium medium) { - switch (medium) { - case UpgradePathInfo::MDNS: - return Medium::MDNS; - case UpgradePathInfo::BLUETOOTH: - return Medium::BLUETOOTH; - case UpgradePathInfo::WIFI_HOTSPOT: - return Medium::WIFI_HOTSPOT; - case UpgradePathInfo::BLE: - return Medium::BLE; - case UpgradePathInfo::WIFI_LAN: - return Medium::WIFI_LAN; - case UpgradePathInfo::WIFI_AWARE: - return Medium::WIFI_AWARE; - case UpgradePathInfo::NFC: - return Medium::NFC; - case UpgradePathInfo::WIFI_DIRECT: - return Medium::WIFI_DIRECT; - case UpgradePathInfo::WEB_RTC: - return Medium::WEB_RTC; - default: - return Medium::UNKNOWN_MEDIUM; - } -} - -ConnectionRequestFrame::Medium MediumToConnectionRequestMedium(Medium medium) { - switch (medium) { - case Medium::MDNS: - return ConnectionRequestFrame::MDNS; - case Medium::BLUETOOTH: - return ConnectionRequestFrame::BLUETOOTH; - case Medium::WIFI_HOTSPOT: - return ConnectionRequestFrame::WIFI_HOTSPOT; - case Medium::BLE: - return ConnectionRequestFrame::BLE; - case Medium::WIFI_LAN: - return ConnectionRequestFrame::WIFI_LAN; - case Medium::WIFI_AWARE: - return ConnectionRequestFrame::WIFI_AWARE; - case Medium::NFC: - return ConnectionRequestFrame::NFC; - case Medium::WIFI_DIRECT: - return ConnectionRequestFrame::WIFI_DIRECT; - case Medium::WEB_RTC: - return ConnectionRequestFrame::WEB_RTC; - default: - return ConnectionRequestFrame::UNKNOWN_MEDIUM; - } -} - -Medium ConnectionRequestMediumToMedium(ConnectionRequestFrame::Medium medium) { - switch (medium) { - case ConnectionRequestFrame::MDNS: - return Medium::MDNS; - case ConnectionRequestFrame::BLUETOOTH: - return Medium::BLUETOOTH; - case ConnectionRequestFrame::WIFI_HOTSPOT: - return Medium::WIFI_HOTSPOT; - case ConnectionRequestFrame::BLE: - return Medium::BLE; - case ConnectionRequestFrame::WIFI_LAN: - return Medium::WIFI_LAN; - case ConnectionRequestFrame::WIFI_AWARE: - return Medium::WIFI_AWARE; - case ConnectionRequestFrame::NFC: - return Medium::NFC; - case ConnectionRequestFrame::WIFI_DIRECT: - return Medium::WIFI_DIRECT; - case ConnectionRequestFrame::WEB_RTC: - return Medium::WEB_RTC; - default: - return Medium::UNKNOWN_MEDIUM; - } -} - -std::vector ConnectionRequestMediumsToMediums( - const ConnectionRequestFrame& frame) { - std::vector result; - for (const auto& int_medium : frame.mediums()) { - result.push_back(ConnectionRequestMediumToMedium( - static_cast(int_medium))); - } - return result; -} - -} // namespace parser -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/offline_frames.h b/cpp/core_v2/internal/offline_frames.h deleted file mode 100644 index 0b9f6614..00000000 --- a/cpp/core_v2/internal/offline_frames.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef CORE_V2_INTERNAL_OFFLINE_FRAMES_H_ -#define CORE_V2_INTERNAL_OFFLINE_FRAMES_H_ - -#include -#include - -#include "core_v2/options.h" -#include "proto/connections/offline_wire_formats.pb.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/exception.h" -#include "proto/connections_enums.pb.h" - -namespace location { -namespace nearby { -namespace connections { -namespace parser { - -using UpgradePathInfo = BandwidthUpgradeNegotiationFrame::UpgradePathInfo; - -// Serialize/Deserialize Nearby Connections Protocol messages. - -// Parses incoming message. -// Returns OfflineFrame if parser was able to understand it, or -// Exception::kInvalidProtocolBuffer, if parser failed. -ExceptionOr FromBytes(const ByteArray& offline_frame_bytes); - -// Returns FrameType of a parsed message, or -// V1Frame::UNKNOWN_FRAME_TYPE, if frame contents is not recognized. -V1Frame::FrameType GetFrameType(const OfflineFrame& offline_frame); - -// Builds Connection Request / Response messages. -ByteArray ForConnectionRequest( - const std::string& endpoint_id, const ByteArray& endpoint_info, - std::int32_t nonce, const std::vector& mediums); -ByteArray ForConnectionResponse(std::int32_t status); - -// Builds Payload transfer messages. -ByteArray ForDataPayloadTransfer( - const PayloadTransferFrame::PayloadHeader& header, - const PayloadTransferFrame::PayloadChunk& chunk); -ByteArray ForControlPayloadTransfer( - const PayloadTransferFrame::PayloadHeader& header, - const PayloadTransferFrame::ControlMessage& control); - -// Builds Bandwidth Upgrade [BWU] messages. -ByteArray ForBwuIntroduction(const std::string& endpoint_id); -ByteArray ForBwuWifiHotspotPathAvailable(const std::string& ssid, - const std::string& password, - std::int32_t port); -ByteArray ForBwuWifiLanPathAvailable(const std::string& ip_address, - std::int32_t port); -ByteArray ForBwuBluetoothPathAvailable(const std::string& service_id, - const std::string& mac_address); -ByteArray ForBwuWebrtcPathAvailable(const std::string& peer_id); -ByteArray ForBwuFailure(const UpgradePathInfo& info); -ByteArray ForBwuLastWrite(); -ByteArray ForBwuSafeToClose(); - -ByteArray ForKeepAlive(); - -UpgradePathInfo::Medium MediumToUpgradePathInfoMedium(Medium medium); -Medium UpgradePathInfoMediumToMedium(UpgradePathInfo::Medium medium); - -ConnectionRequestFrame::Medium MediumToConnectionRequestMedium(Medium medium); -Medium ConnectionRequestMediumToMedium(ConnectionRequestFrame::Medium medium); -std::vector ConnectionRequestMediumsToMediums( - const ConnectionRequestFrame& connection_request_frame); - -} // namespace parser -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_OFFLINE_FRAMES_H_ diff --git a/cpp/core_v2/internal/offline_frames_test.cc b/cpp/core_v2/internal/offline_frames_test.cc deleted file mode 100644 index 8d0a402c..00000000 --- a/cpp/core_v2/internal/offline_frames_test.cc +++ /dev/null @@ -1,301 +0,0 @@ -#include "core_v2/internal/offline_frames.h" - -#include -#include -#include -#include - -#include "proto/connections/offline_wire_formats.pb.h" -#include "platform_v2/base/byte_array.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -namespace location { -namespace nearby { -namespace connections { -namespace parser { -namespace { - -using Medium = proto::connections::Medium; -using ::testing::EqualsProto; - -constexpr absl::string_view kEndpointId{"ABC"}; -constexpr absl::string_view kEndpointName{"XYZ"}; -constexpr int kNonce = 1234; -constexpr std::array kMediums = { - Medium::MDNS, Medium::BLUETOOTH, Medium::WIFI_HOTSPOT, - Medium::BLE, Medium::WIFI_LAN, Medium::WIFI_AWARE, - Medium::NFC, Medium::WIFI_DIRECT, Medium::WEB_RTC, -}; - -TEST(OfflineFramesTest, CanParseMessageFromBytes) { - OfflineFrame tx_message; - - { - tx_message.set_version(OfflineFrame::V1); - auto* v1_frame = tx_message.mutable_v1(); - auto* sub_frame = v1_frame->mutable_connection_request(); - - v1_frame->set_type(V1Frame::CONNECTION_REQUEST); - sub_frame->set_endpoint_id(kEndpointId); - sub_frame->set_endpoint_name(kEndpointName); - sub_frame->set_endpoint_info(kEndpointName); - sub_frame->set_nonce(kNonce); - for (auto& medium : kMediums) { - sub_frame->add_mediums(MediumToConnectionRequestMedium(medium)); - } - } - auto serialized_bytes = ByteArray(tx_message.SerializeAsString()); - auto ret_value = FromBytes(serialized_bytes); - ASSERT_TRUE(ret_value.ok()); - const auto& rx_message = ret_value.result(); - EXPECT_THAT(rx_message, EqualsProto(tx_message)); - EXPECT_EQ(GetFrameType(rx_message), V1Frame::CONNECTION_REQUEST); - EXPECT_EQ( - ConnectionRequestMediumsToMediums(rx_message.v1().connection_request()), - std::vector(kMediums.begin(), kMediums.end())); -} - -TEST(OfflineFramesTest, CanGenerateConnectionRequest) { - constexpr char kExpected[] = - R"pb( - version: V1 - v1: < - type: CONNECTION_REQUEST - connection_request: < - endpoint_id: "ABC" - endpoint_name: "XYZ" - endpoint_info: "XYZ" - nonce: 1234 - mediums: MDNS - mediums: BLUETOOTH - mediums: WIFI_HOTSPOT - mediums: BLE - mediums: WIFI_LAN - mediums: WIFI_AWARE - mediums: NFC - mediums: WIFI_DIRECT - mediums: WEB_RTC - > - >)pb"; - ByteArray bytes = ForConnectionRequest( - std::string(kEndpointId), ByteArray{std::string(kEndpointName)}, kNonce, - std::vector(kMediums.begin(), kMediums.end())); - auto response = FromBytes(bytes); - ASSERT_TRUE(response.ok()); - OfflineFrame message = FromBytes(bytes).result(); - EXPECT_THAT(message, EqualsProto(kExpected)); -} - -TEST(OfflineFramesTest, CanGenerateConnectionResponse) { - constexpr char kExpected[] = - R"pb( - version: V1 - v1: < - type: CONNECTION_RESPONSE - connection_response: < - status: 1 - response: REJECT - > - >)pb"; - ByteArray bytes = ForConnectionResponse(1); - auto response = FromBytes(bytes); - ASSERT_TRUE(response.ok()); - OfflineFrame message = FromBytes(bytes).result(); - EXPECT_THAT(message, EqualsProto(kExpected)); -} - -TEST(OfflineFramesTest, CanGenerateControlPayloadTransfer) { - PayloadTransferFrame::PayloadHeader header; - PayloadTransferFrame::ControlMessage control; - header.set_id(12345); - header.set_type(PayloadTransferFrame::PayloadHeader::BYTES); - header.set_total_size(1024); - control.set_event(PayloadTransferFrame::ControlMessage::PAYLOAD_CANCELED); - control.set_offset(150); - - constexpr char kExpected[] = - R"pb( - version: V1 - v1: < - type: PAYLOAD_TRANSFER - payload_transfer: < - packet_type: CONTROL, - payload_header: < type: BYTES id: 12345 total_size: 1024 > - control_message: < event: PAYLOAD_CANCELED offset: 150 > - > - >)pb"; - ByteArray bytes = ForControlPayloadTransfer(header, control); - auto response = FromBytes(bytes); - ASSERT_TRUE(response.ok()); - OfflineFrame message = FromBytes(bytes).result(); - EXPECT_THAT(message, EqualsProto(kExpected)); -} - -TEST(OfflineFramesTest, CanGenerateDataPayloadTransfer) { - PayloadTransferFrame::PayloadHeader header; - PayloadTransferFrame::PayloadChunk chunk; - header.set_id(12345); - header.set_type(PayloadTransferFrame::PayloadHeader::BYTES); - header.set_total_size(1024); - chunk.set_body("payload data"); - chunk.set_offset(150); - chunk.set_flags(1); - - constexpr char kExpected[] = - R"pb( - version: V1 - v1: < - type: PAYLOAD_TRANSFER - payload_transfer: < - packet_type: DATA, - payload_header: < type: BYTES id: 12345 total_size: 1024 > - payload_chunk: < flags: 1 offset: 150 body: "payload data" > - > - >)pb"; - ByteArray bytes = ForDataPayloadTransfer(header, chunk); - auto response = FromBytes(bytes); - ASSERT_TRUE(response.ok()); - OfflineFrame message = FromBytes(bytes).result(); - EXPECT_THAT(message, EqualsProto(kExpected)); -} - -TEST(OfflineFramesTest, CanGenerateBwuWifiHotspotPathAvailable) { - constexpr char kExpected[] = - R"pb( - version: V1 - v1: < - type: BANDWIDTH_UPGRADE_NEGOTIATION - bandwidth_upgrade_negotiation: < - event_type: UPGRADE_PATH_AVAILABLE - upgrade_path_info: < - medium: WIFI_HOTSPOT - wifi_hotspot_credentials: < - ssid: "ssid" - password: "password" - port: 1234 - > - > - > - >)pb"; - ByteArray bytes = ForBwuWifiHotspotPathAvailable("ssid", "password", 1234); - auto response = FromBytes(bytes); - ASSERT_TRUE(response.ok()); - OfflineFrame message = FromBytes(bytes).result(); - EXPECT_THAT(message, EqualsProto(kExpected)); -} - -TEST(OfflineFramesTest, CanGenerateBwuWifiLanPathAvailable) { - constexpr char kExpected[] = - R"pb( - version: V1 - v1: < - type: BANDWIDTH_UPGRADE_NEGOTIATION - bandwidth_upgrade_negotiation: < - event_type: UPGRADE_PATH_AVAILABLE - upgrade_path_info: < - medium: WIFI_LAN - wifi_lan_socket: < ip_address: "\x01\x02\x03\x04" wifi_port: 1234 > - > - > - >)pb"; - ByteArray bytes = ForBwuWifiLanPathAvailable("\x01\x02\x03\x04", 1234); - auto response = FromBytes(bytes); - ASSERT_TRUE(response.ok()); - OfflineFrame message = FromBytes(bytes).result(); - EXPECT_THAT(message, EqualsProto(kExpected)); -} - -TEST(OfflineFramesTest, CanGenerateBwuBluetoothPathAvailable) { - constexpr char kExpected[] = - R"pb( - version: V1 - v1: < - type: BANDWIDTH_UPGRADE_NEGOTIATION - bandwidth_upgrade_negotiation: < - event_type: UPGRADE_PATH_AVAILABLE - upgrade_path_info: < - medium: BLUETOOTH - bluetooth_credentials: < - service_name: "service" - mac_address: "\x11\x22\x33\x44\x55\x66" - > - > - > - >)pb"; - ByteArray bytes = - ForBwuBluetoothPathAvailable("service", "\x11\x22\x33\x44\x55\x66"); - auto response = FromBytes(bytes); - ASSERT_TRUE(response.ok()); - OfflineFrame message = FromBytes(bytes).result(); - EXPECT_THAT(message, EqualsProto(kExpected)); -} - -TEST(OfflineFramesTest, CanGenerateBwuLastWrite) { - constexpr char kExpected[] = - R"pb( - version: V1 - v1: < - type: BANDWIDTH_UPGRADE_NEGOTIATION - bandwidth_upgrade_negotiation: < event_type: LAST_WRITE_TO_PRIOR_CHANNEL > - >)pb"; - ByteArray bytes = ForBwuLastWrite(); - auto response = FromBytes(bytes); - ASSERT_TRUE(response.ok()); - OfflineFrame message = FromBytes(bytes).result(); - EXPECT_THAT(message, EqualsProto(kExpected)); -} - -TEST(OfflineFramesTest, CanGenerateBwuSafeToClose) { - constexpr char kExpected[] = - R"pb( - version: V1 - v1: < - type: BANDWIDTH_UPGRADE_NEGOTIATION - bandwidth_upgrade_negotiation: < event_type: SAFE_TO_CLOSE_PRIOR_CHANNEL > - >)pb"; - ByteArray bytes = ForBwuSafeToClose(); - auto response = FromBytes(bytes); - ASSERT_TRUE(response.ok()); - OfflineFrame message = FromBytes(bytes).result(); - EXPECT_THAT(message, EqualsProto(kExpected)); -} - -TEST(OfflineFramesTest, CanGenerateBwuIntroduction) { - constexpr char kExpected[] = - R"pb( - version: V1 - v1: < - type: BANDWIDTH_UPGRADE_NEGOTIATION - bandwidth_upgrade_negotiation: < - event_type: CLIENT_INTRODUCTION - client_introduction: < endpoint_id: "ABC" > - > - >)pb"; - ByteArray bytes = ForBwuIntroduction(std::string(kEndpointId)); - auto response = FromBytes(bytes); - ASSERT_TRUE(response.ok()); - OfflineFrame message = FromBytes(bytes).result(); - EXPECT_THAT(message, EqualsProto(kExpected)); -} - -TEST(OfflineFramesTest, CanGenerateKeepAlive) { - constexpr char kExpected[] = - R"pb( - version: V1 - v1: < - type: KEEP_ALIVE - keep_alive: <> - >)pb"; - ByteArray bytes = ForKeepAlive(); - auto response = FromBytes(bytes); - ASSERT_TRUE(response.ok()); - OfflineFrame message = FromBytes(bytes).result(); - EXPECT_THAT(message, EqualsProto(kExpected)); -} - -} // namespace -} // namespace parser -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/offline_service_controller.cc b/cpp/core_v2/internal/offline_service_controller.cc deleted file mode 100644 index 1ae47348..00000000 --- a/cpp/core_v2/internal/offline_service_controller.cc +++ /dev/null @@ -1,80 +0,0 @@ -#include "core_v2/internal/offline_service_controller.h" - -#include - -namespace location { -namespace nearby { -namespace connections { - -OfflineServiceController::~OfflineServiceController() { Stop(); } - -void OfflineServiceController::Stop() { - if (stop_.Set(true)) return; - payload_manager_.DisconnectFromEndpointManager(); - pcp_manager_.DisconnectFromEndpointManager(); -} - -Status OfflineServiceController::StartAdvertising( - ClientProxy* client, const std::string& service_id, - const ConnectionOptions& options, const ConnectionRequestInfo& info) { - return pcp_manager_.StartAdvertising(client, service_id, options, info); -} - -void OfflineServiceController::StopAdvertising(ClientProxy* client) { - pcp_manager_.StopAdvertising(client); -} - -Status OfflineServiceController::StartDiscovery( - ClientProxy* client, const std::string& service_id, - const ConnectionOptions& options, const DiscoveryListener& listener) { - return pcp_manager_.StartDiscovery(client, service_id, options, listener); -} - -void OfflineServiceController::StopDiscovery(ClientProxy* client) { - pcp_manager_.StopDiscovery(client); -} - -Status OfflineServiceController::RequestConnection( - ClientProxy* client, const std::string& endpoint_id, - const ConnectionRequestInfo& info, const ConnectionOptions& options) { - return pcp_manager_.RequestConnection(client, endpoint_id, info, options); -} - -Status OfflineServiceController::AcceptConnection( - ClientProxy* client, const std::string& endpoint_id, - const PayloadListener& listener) { - return pcp_manager_.AcceptConnection(client, endpoint_id, listener); -} - -Status OfflineServiceController::RejectConnection( - ClientProxy* client, const std::string& endpoint_id) { - return pcp_manager_.RejectConnection(client, endpoint_id); -} - -void OfflineServiceController::InitiateBandwidthUpgrade( - ClientProxy* client, const std::string& endpoint_id) { - NEARBY_LOGS(INFO) << "Client " << client->GetClientId() - << " initiated a manual bandwidth upgrade with endpoint id=" - << endpoint_id; - bwu_manager_.InitiateBwuForEndpoint(client, endpoint_id); -} - -void OfflineServiceController::SendPayload( - ClientProxy* client, const std::vector& endpoint_ids, - Payload payload) { - payload_manager_.SendPayload(client, endpoint_ids, std::move(payload)); -} - -Status OfflineServiceController::CancelPayload(ClientProxy* client, - std::int64_t payload_id) { - return payload_manager_.CancelPayload(client, payload_id); -} - -void OfflineServiceController::DisconnectFromEndpoint( - ClientProxy* client, const std::string& endpoint_id) { - endpoint_manager_.UnregisterEndpoint(client, endpoint_id); -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/offline_service_controller.h b/cpp/core_v2/internal/offline_service_controller.h deleted file mode 100644 index 7b6a1c5a..00000000 --- a/cpp/core_v2/internal/offline_service_controller.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef CORE_V2_INTERNAL_OFFLINE_SERVICE_CONTROLLER_H_ -#define CORE_V2_INTERNAL_OFFLINE_SERVICE_CONTROLLER_H_ - -#include -#include -#include - -#include "core_v2/internal/bwu_manager.h" -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/endpoint_channel_manager.h" -#include "core_v2/internal/endpoint_manager.h" -#include "core_v2/internal/mediums/mediums.h" -#include "core_v2/internal/payload_manager.h" -#include "core_v2/internal/pcp_manager.h" -#include "core_v2/internal/service_controller.h" -#include "core_v2/listeners.h" -#include "core_v2/options.h" -#include "core_v2/payload.h" -#include "core_v2/status.h" - -namespace location { -namespace nearby { -namespace connections { - -class OfflineServiceController : public ServiceController { - public: - OfflineServiceController() = default; - ~OfflineServiceController() override; - - Status StartAdvertising(ClientProxy* client, const std::string& service_id, - const ConnectionOptions& options, - const ConnectionRequestInfo& info) override; - void StopAdvertising(ClientProxy* client) override; - - Status StartDiscovery(ClientProxy* client, const std::string& service_id, - const ConnectionOptions& options, - const DiscoveryListener& listener) override; - void StopDiscovery(ClientProxy* client) override; - - Status RequestConnection(ClientProxy* client, const std::string& endpoint_id, - const ConnectionRequestInfo& info, - const ConnectionOptions& options) override; - Status AcceptConnection(ClientProxy* client, const std::string& endpoint_id, - const PayloadListener& listener) override; - Status RejectConnection(ClientProxy* client, - const std::string& endpoint_id) override; - - void InitiateBandwidthUpgrade(ClientProxy* client, - const std::string& endpoint_id) override; - - void SendPayload(ClientProxy* client, - const std::vector& endpoint_ids, - Payload payload) override; - Status CancelPayload(ClientProxy* client, Payload::Id payload_id) override; - - void DisconnectFromEndpoint(ClientProxy* client, - const std::string& endpoint_id) override; - - void Stop(); - - private: - // Note that the order of declaration of these is crucial, because we depend - // on the destructors running (strictly) in the reverse order; a deviation - // from that will lead to crashes at runtime. - AtomicBoolean stop_{false}; - Mediums mediums_; - EndpointChannelManager channel_manager_; - EndpointManager endpoint_manager_{&channel_manager_}; - PayloadManager payload_manager_{endpoint_manager_}; - BwuManager bwu_manager_{ - mediums_, endpoint_manager_, channel_manager_, {}, {}}; - PcpManager pcp_manager_{mediums_, channel_manager_, endpoint_manager_, - bwu_manager_}; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_OFFLINE_SERVICE_CONTROLLER_H_ diff --git a/cpp/core_v2/internal/p2p_cluster_pcp_handler.cc b/cpp/core_v2/internal/p2p_cluster_pcp_handler.cc deleted file mode 100644 index eb6f0773..00000000 --- a/cpp/core_v2/internal/p2p_cluster_pcp_handler.cc +++ /dev/null @@ -1,1175 +0,0 @@ -#include "core_v2/internal/p2p_cluster_pcp_handler.h" - -#include "core_v2/internal/base_pcp_handler.h" -#include "core_v2/internal/ble_advertisement.h" -#include "core_v2/internal/ble_endpoint_channel.h" -#include "core_v2/internal/bluetooth_endpoint_channel.h" -#include "core_v2/internal/bwu_manager.h" -#include "core_v2/internal/mediums/utils.h" -#include "core_v2/internal/mediums/webrtc/webrtc_socket_wrapper.h" -#include "core_v2/internal/webrtc_endpoint_channel.h" -#include "core_v2/internal/wifi_lan_endpoint_channel.h" -#include "platform_v2/base/types.h" -#include "platform_v2/public/crypto.h" -#include "proto/connections_enums.pb.h" -#include "absl/functional/bind_front.h" -#include "absl/strings/escaping.h" - -namespace location { -namespace nearby { -namespace connections { - -ByteArray P2pClusterPcpHandler::GenerateHash(const std::string& source, - size_t size) { - return Utils::Sha256Hash(source, size); -} - -bool P2pClusterPcpHandler::ShouldAdvertiseBluetoothMacOverBle( - PowerLevel power_level) { - return power_level == PowerLevel::kHighPower; -} - -bool P2pClusterPcpHandler::ShouldAcceptBluetoothConnections( - const ConnectionOptions& options) { - return options.enable_bluetooth_listening; -} - -P2pClusterPcpHandler::P2pClusterPcpHandler( - Mediums* mediums, EndpointManager* endpoint_manager, - EndpointChannelManager* endpoint_channel_manager, BwuManager* bwu_manager, - Pcp pcp) - : BasePcpHandler(mediums, endpoint_manager, endpoint_channel_manager, - bwu_manager, pcp), - bluetooth_radio_(mediums->GetBluetoothRadio()), - bluetooth_medium_(mediums->GetBluetoothClassic()), - ble_medium_(mediums->GetBle()), - wifi_lan_medium_(mediums->GetWifiLan()), - webrtc_medium_(mediums->GetWebRtc()) {} - -// Returns a vector or mediums sorted in order or decreasing priority for -// all the supported mediums. -// Example: WiFi_LAN, WEB_RTC, BT, BLE -std::vector -P2pClusterPcpHandler::GetConnectionMediumsByPriority() { - std::vector mediums; - if (wifi_lan_medium_.IsAvailable()) { - mediums.push_back(proto::connections::WIFI_LAN); - } - if (webrtc_medium_.IsAvailable()) { - mediums.push_back(proto::connections::WEB_RTC); - } - if (bluetooth_medium_.IsAvailable()) { - mediums.push_back(proto::connections::BLUETOOTH); - } - if (ble_medium_.IsAvailable()) { - mediums.push_back(proto::connections::BLE); - } - return mediums; -} - -proto::connections::Medium P2pClusterPcpHandler::GetDefaultUpgradeMedium() { - return proto::connections::WIFI_LAN; -} - -BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartAdvertisingImpl( - ClientProxy* client, const std::string& service_id, - const std::string& local_endpoint_id, const ByteArray& local_endpoint_info, - const ConnectionOptions& options) { - std::vector mediums_started_successfully; - - WebRtcState web_rtc_state{WebRtcState::kUnconnectable}; - if (options.allowed.web_rtc) { - proto::connections::Medium webrtc_medium = - StartListeningForWebRtcConnections( - client, service_id, local_endpoint_id, local_endpoint_info); - if (webrtc_medium != proto::connections::UNKNOWN_MEDIUM) { - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::StartAdvertisingImpl: WebRtc added"); - mediums_started_successfully.push_back(webrtc_medium); - web_rtc_state = WebRtcState::kConnectable; - } - } - - if (options.allowed.wifi_lan) { - const ByteArray wifi_lan_hash = - GenerateHash(service_id, WifiLanServiceInfo::kServiceIdHashLength); - proto::connections::Medium wifi_lan_medium = StartWifiLanAdvertising( - client, service_id, wifi_lan_hash, local_endpoint_id, - local_endpoint_info, web_rtc_state); - if (wifi_lan_medium != proto::connections::UNKNOWN_MEDIUM) { - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::StartAdvertisingImpl: WifiLan added"); - mediums_started_successfully.push_back(wifi_lan_medium); - } - } - - if (options.allowed.bluetooth) { - const ByteArray bluetooth_hash = - GenerateHash(service_id, BluetoothDeviceName::kServiceIdHashLength); - proto::connections::Medium bluetooth_medium = StartBluetoothAdvertising( - client, service_id, bluetooth_hash, local_endpoint_id, - local_endpoint_info, web_rtc_state); - if (bluetooth_medium != proto::connections::UNKNOWN_MEDIUM) { - NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartAdvertisingImpl: BT added"); - mediums_started_successfully.push_back(bluetooth_medium); - } - } - - if (options.allowed.ble) { - proto::connections::Medium ble_medium = - StartBleAdvertising(client, service_id, local_endpoint_id, - local_endpoint_info, options, web_rtc_state); - if (ble_medium != proto::connections::UNKNOWN_MEDIUM) { - NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartAdvertisingImpl: Ble added"); - mediums_started_successfully.push_back(ble_medium); - } - } - - if (mediums_started_successfully.empty()) { - NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartAdvertisingImpl: not started"); - return { - .status = {Status::kBluetoothError}, - }; - } - - // The rest of the operations for startAdvertising() will continue - // asynchronously via - // IncomingBluetoothConnectionProcessor.onIncomingBluetoothConnection(), so - // leave it to that to signal any errors that may occur. - return { - .status = {Status::kSuccess}, - .mediums = std::move(mediums_started_successfully), - }; -} - -Status P2pClusterPcpHandler::StopAdvertisingImpl(ClientProxy* client) { - bluetooth_medium_.TurnOffDiscoverability(); - bluetooth_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId()); - - ble_medium_.StopAdvertising(client->GetAdvertisingServiceId()); - ble_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId()); - - webrtc_medium_.StopAcceptingConnections(); - - wifi_lan_medium_.StopAdvertising(client->GetAdvertisingServiceId()); - wifi_lan_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId()); - - return {Status::kSuccess}; -} - -bool P2pClusterPcpHandler::IsRecognizedBluetoothEndpoint( - const std::string& name_string, const std::string& service_id, - const BluetoothDeviceName& name) const { - if (!name.IsValid()) { - NEARBY_LOG( - INFO, - "P2pClusterPcpHandler::IsRecognizedBluetoothEndpoint: name is invalid"); - return false; - } - - if (name.GetPcp() != GetPcp()) { - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::IsRecognizedBluetoothEndpoint: Pcp is " - "not matched; name.Pcp=%d, Pcp=%d", - name.GetPcp(), GetPcp()); - return false; - } - - ByteArray expected_service_id_hash = - GenerateHash(service_id, BluetoothDeviceName::kServiceIdHashLength); - - if (name.GetServiceIdHash() != expected_service_id_hash) { - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::IsRecognizedBluetoothEndpoint: service " - "id hash is " - "not matched; name.service_id_hash=%s, expected=%s", - name.GetServiceIdHash().data(), expected_service_id_hash.data()); - return false; - } - - return true; -} - -void P2pClusterPcpHandler::BluetoothDeviceDiscoveredHandler( - ClientProxy* client, const std::string& service_id, - BluetoothDevice& device) { - RunOnPcpHandlerThread([this, client, service_id, &device]() { - // Make sure we are still discovering before proceeding. - if (!client->IsDiscovering()) { - NEARBY_LOG(INFO, - "BT discovery handler (FOUND) [client=%p, service=%s]: not " - "in discovery mode", - client, service_id.c_str()); - return; - } - - // Parse the Bluetooth device name. - const std::string& device_name_string = device.GetName(); - BluetoothDeviceName device_name(device_name_string); - - // Make sure the Bluetooth device name points to a valid - // endpoint we're discovering. - if (!IsRecognizedBluetoothEndpoint(device_name_string, service_id, - device_name)) - return; - - // Report the discovered endpoint to the client. - NEARBY_LOGS(INFO) - << "Invoking BasePcpHandler::OnEndpointFound() for BT service=" - << service_id << "; id=" << device_name.GetEndpointId() << "; name=" - << absl::BytesToHexString(device_name.GetEndpointInfo().data()); - OnEndpointFound(client, - std::make_shared(BluetoothEndpoint{ - { - device_name.GetEndpointId(), - device_name.GetEndpointInfo(), - service_id, - proto::connections::Medium::BLUETOOTH, - device_name.GetWebRtcState() - }, - device, - })); - }); -} - -void P2pClusterPcpHandler::BluetoothDeviceLostHandler( - ClientProxy* client, const std::string& service_id, - BluetoothDevice& device) { - const std::string& device_name_string = device.GetName(); - RunOnPcpHandlerThread([this, client, service_id, device_name_string]() { - // Make sure we are still discovering before proceeding. - if (!client->IsDiscovering()) { - NEARBY_LOG(INFO, - "BT discovery handler (LOST) [client=%p, service=%s]: not " - "in discovery mode", - client, service_id.c_str()); - return; - } - - // Parse the Bluetooth device name. - BluetoothDeviceName device_name(device_name_string); - - // Make sure the Bluetooth device name points to a valid - // endpoint we're discovering. - if (!IsRecognizedBluetoothEndpoint(device_name_string, service_id, - device_name)) - return; - - // Report the discovered endpoint to the client. - NEARBY_LOG(INFO, - "BT discovery handler (LOST) [client=%p, service=%s]: report " - "to client", - client, service_id.c_str()); - OnEndpointLost(client, DiscoveredEndpoint{ - device_name.GetEndpointId(), - device_name.GetEndpointInfo(), - service_id, - proto::connections::Medium::BLUETOOTH, - WebRtcState::kUndefined - }); - }); -} - -bool P2pClusterPcpHandler::IsRecognizedBleEndpoint( - const std::string& service_id, - const BleAdvertisement& advertisement) const { - if (!advertisement.IsValid()) { - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::IsRecognizedBleEndpoint: advertisement " - "is invalid"); - return false; - } - - if (advertisement.GetVersion() != kBleAdvertisementVersion) { - NEARBY_LOG( - INFO, - "P2pClusterPcpHandler::IsRecognizedBluetoothEndpoint: Version is " - "not matched; advertisement.Version=%d, Version=%d", - advertisement.GetVersion(), kBleAdvertisementVersion); - return false; - } - - if (advertisement.GetPcp() != GetPcp()) { - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::IsRecognizedBluetoothEndpoint: Pcp is " - "not matched; advertisement.Pcp=%d, Pcp=%d", - advertisement.GetPcp(), GetPcp()); - return false; - } - - // Check ServiceId for normal advertisement. - // ServiceIdHash is empty for fast advertisement. - if (!advertisement.IsFastAdvertisement()) { - ByteArray expected_service_id_hash = - GenerateHash(service_id, BleAdvertisement::kServiceIdHashLength); - - if (advertisement.GetServiceIdHash() != expected_service_id_hash) { - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::IsRecognizedBleEndpoint: service " - "id hash is " - "not matched; advertisement.service_id_hash=%s, expected=%s", - advertisement.GetServiceIdHash().data(), - expected_service_id_hash.data()); - return false; - } - } - - return true; -} - -void P2pClusterPcpHandler::BlePeripheralDiscoveredHandler( - ClientProxy* client, BlePeripheral& peripheral, - const std::string& service_id, const ByteArray& advertisement_bytes, - bool fast_advertisement) { - RunOnPcpHandlerThread([this, client, &peripheral, service_id, - advertisement_bytes, fast_advertisement]() { - // Make sure we are still discovering before proceeding. - if (!client->IsDiscovering()) { - NEARBY_LOG(INFO, - "Ble scanning handler (FOUND) [client=%p, service_id=%s]: not " - "in discovery mode", - client, service_id.c_str()); - return; - } - - // Parse the BLE advertisement bytes. - BleAdvertisement advertisement(fast_advertisement, advertisement_bytes); - - // Make sure the BLE advertisement points to a valid - // endpoint we're discovering. - if (!IsRecognizedBleEndpoint(service_id, advertisement)) return; - - // Store all the state we need to be able to re-create a BleEndpoint - // in BlePeripheralLostHandler, since that isn't privy to - // the bytes of the ble advertisement itself. - found_ble_endpoints_.emplace( - peripheral.GetName(), - BleEndpointState(advertisement.GetEndpointId(), - advertisement.GetEndpointInfo())); - - // Report the discovered endpoint to the client. - NEARBY_LOGS(INFO) - << "Invoking BasePcpHandler::OnEndpointFound() for Ble service=" - << service_id << "; id=" << advertisement.GetEndpointId() << "; name=" - << absl::BytesToHexString(advertisement.GetEndpointInfo().data()); - OnEndpointFound(client, std::make_shared(BleEndpoint{ - { - advertisement.GetEndpointId(), - advertisement.GetEndpointInfo(), - service_id, - proto::connections::Medium::BLE, - advertisement.GetWebRtcState() - }, - peripheral, - })); - - // Make sure we can connect to this device via Classic Bluetooth. - std::string remote_bluetooth_mac_address = - advertisement.GetBluetoothMacAddress(); - if (remote_bluetooth_mac_address.empty()) { - NEARBY_LOGS(INFO) - << "No Bluetooth Classic MAC address found in advertisement"; - return; - } - - BluetoothDevice remote_bluetooth_device = - bluetooth_medium_.GetRemoteDevice(remote_bluetooth_mac_address); - if (!remote_bluetooth_device.IsValid()) { - NEARBY_LOGS(INFO) << "A valid Bluetooth device could not be derived from " - "the MAC address " - << remote_bluetooth_mac_address; - return; - } - - OnEndpointFound(client, - std::make_shared(BluetoothEndpoint{ - { - advertisement.GetEndpointId(), - advertisement.GetEndpointInfo(), - service_id, - proto::connections::Medium::BLUETOOTH, - advertisement.GetWebRtcState(), - }, - remote_bluetooth_device, - })); - }); -} - -void P2pClusterPcpHandler::BlePeripheralLostHandler( - ClientProxy* client, BlePeripheral& peripheral, - const std::string& service_id) { - std::string peripheral_name = peripheral.GetName(); - NEARBY_LOG(INFO, "Ble: [LOST, SCHED] peripheral_name=%s", - peripheral_name.c_str()); - RunOnPcpHandlerThread([this, client, service_id, &peripheral]() { - // Make sure we are still discovering before proceeding. - if (!client->IsDiscovering()) { - NEARBY_LOG(INFO, - "Ble scanning handler (LOST) [client=%p, service_id=%s]: not " - "in scanning mode", - client, service_id.c_str()); - return; - } - - // Remove this BlePeripheral from found_ble_endpoints_, and - // report the endpoint as lost to the client. - auto item = found_ble_endpoints_.find(peripheral.GetName()); - if (item != found_ble_endpoints_.end()) { - BleEndpointState ble_endpoint_state(item->second); - found_ble_endpoints_.erase(item); - - // Report the discovered endpoint to the client. - NEARBY_LOG(INFO, - "Ble scanning handler (LOST) [client=%p, " - "service_id=%s]: report to client", - client, service_id.c_str()); - OnEndpointLost(client, DiscoveredEndpoint{ - ble_endpoint_state.endpoint_id, - ble_endpoint_state.endpoint_info, - service_id, - proto::connections::Medium::BLE, - WebRtcState::kUndefined, - }); - } - }); -} - -bool P2pClusterPcpHandler::IsRecognizedWifiLanEndpoint( - const std::string& service_id, - const WifiLanServiceInfo& service_info) const { - if (!service_info.IsValid()) { - NEARBY_LOG( - INFO, - "P2pClusterPcpHandler::IsRecognizedWifiLanEndpoint: name is invalid"); - return false; - } - - if (service_info.GetPcp() != GetPcp()) { - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::IsRecognizedWifiLanEndpoint: Pcp is " - "not matched; name.Pcp=%d, Pcp=%d", - service_info.GetPcp(), GetPcp()); - return false; - } - - ByteArray expected_service_id_hash = - GenerateHash(service_id, BluetoothDeviceName::kServiceIdHashLength); - - if (service_info.GetServiceIdHash() != expected_service_id_hash) { - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::IsRecognizedWifiLanEndpoint: service " - "id hash is " - "not matched; name.service_id_hash=%s, expected=%s", - service_info.GetServiceIdHash().data(), - expected_service_id_hash.data()); - return false; - } - - return true; -} - -void P2pClusterPcpHandler::WifiLanServiceDiscoveredHandler( - ClientProxy* client, WifiLanService& service, - const std::string& service_id) { - RunOnPcpHandlerThread([this, client, service_id, &service]() { - // Make sure we are still discovering before proceeding. - if (!client->IsDiscovering()) { - NEARBY_LOG( - INFO, - "WifiLan discovery handler (FOUND) [client=%p, service=%s]: not " - "in discovery mode", - client, service_id.c_str()); - return; - } - - // Parse the WifiLan service name. - const std::string& service_info_name = service.GetName(); - WifiLanServiceInfo service_info(service_info_name); - - // Make sure the WifiLan service name points to a valid - // endpoint we're discovering. - if (!IsRecognizedWifiLanEndpoint(service_id, service_info)) return; - - // Report the discovered endpoint to the client. - NEARBY_LOG( - INFO, - "Invoking BasePcpHandler::OnEndpointFound() for WifiLan " - "service=%s; id=%s; name=%s", - service_id.c_str(), service_info.GetEndpointId().c_str(), - absl::BytesToHexString(service_info.GetEndpointInfo().data()).c_str()); - OnEndpointFound(client, std::make_shared(WifiLanEndpoint{ - { - service_info.GetEndpointId(), - service_info.GetEndpointInfo(), - service_id, - proto::connections::Medium::WIFI_LAN, - service_info.GetWebRtcState(), - }, - service, - })); - }); -} - -void P2pClusterPcpHandler::WifiLanServiceLostHandler( - ClientProxy* client, WifiLanService& service, - const std::string& service_id) { - std::string service_info_name = service.GetName(); - NEARBY_LOG(INFO, "WifiLAN: [LOST, SCHED] service_info_name=%s", - service_info_name.c_str()); - RunOnPcpHandlerThread([this, client, service_id, service_info_name]() { - // Make sure we are still discovering before proceeding. - if (!client->IsDiscovering()) { - NEARBY_LOG( - INFO, - "WifiLan discovery handler (LOST) [client=%p, service=%s]: not " - "in discovery mode", - client, service_id.c_str()); - return; - } - - // Parse the WifiLan service name. - WifiLanServiceInfo service_info(service_info_name); - - // Make sure the WifiLan service name points to a valid - // endpoint we're discovering. - if (!IsRecognizedWifiLanEndpoint(service_id, service_info)) return; - - // Report the discovered endpoint to the client. - NEARBY_LOG( - INFO, - "WifiLan discovery handler (LOST) [client=%p, service_id=%s]: report " - "to client", - client, service_id.c_str()); - OnEndpointLost(client, DiscoveredEndpoint{ - service_info.GetEndpointId(), - service_info.GetEndpointInfo(), - service_id, - proto::connections::Medium::WIFI_LAN, - WebRtcState::kUndefined, - }); - }); -} - -BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartDiscoveryImpl( - ClientProxy* client, const std::string& service_id, - const ConnectionOptions& options) { - std::vector mediums_started_successfully; - - if (options.allowed.wifi_lan) { - proto::connections::Medium wifi_lan_medium = StartWifiLanDiscovery( - { - .service_discovered_cb = absl::bind_front( - &P2pClusterPcpHandler::WifiLanServiceDiscoveredHandler, this, - client), - .service_lost_cb = absl::bind_front( - &P2pClusterPcpHandler::WifiLanServiceLostHandler, this, client), - }, - client, service_id); - if (wifi_lan_medium != proto::connections::UNKNOWN_MEDIUM) { - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::StartDiscoveryImpl: WifiLan added"); - mediums_started_successfully.push_back(wifi_lan_medium); - } - } - - if (options.allowed.bluetooth) { - proto::connections::Medium bluetooth_medium = StartBluetoothDiscovery( - { - .device_discovered_cb = absl::bind_front( - &P2pClusterPcpHandler::BluetoothDeviceDiscoveredHandler, this, - client, service_id), - .device_name_changed_cb = absl::bind_front( - &P2pClusterPcpHandler::BluetoothDeviceDiscoveredHandler, this, - client, service_id), - .device_lost_cb = absl::bind_front( - &P2pClusterPcpHandler::BluetoothDeviceLostHandler, this, client, - service_id), - }, - client, service_id); - if (bluetooth_medium != proto::connections::UNKNOWN_MEDIUM) { - NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartDiscoveryImpl: BT added"); - mediums_started_successfully.push_back(bluetooth_medium); - } - } - - if (options.allowed.ble) { - proto::connections::Medium ble_medium = StartBleScanning( - { - .peripheral_discovered_cb = absl::bind_front( - &P2pClusterPcpHandler::BlePeripheralDiscoveredHandler, this, - client), - .peripheral_lost_cb = absl::bind_front( - &P2pClusterPcpHandler::BlePeripheralLostHandler, this, client), - }, - client, service_id, options.fast_advertisement_service_uuid); - if (ble_medium != proto::connections::UNKNOWN_MEDIUM) { - NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartDiscoveryImpl: Ble added"); - mediums_started_successfully.push_back(ble_medium); - } - } - - if (mediums_started_successfully.empty()) { - NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartDiscoveryImpl: nothing added"); - return { - .status = {Status::kBluetoothError}, - }; - } - - return { - .status = {Status::kSuccess}, - .mediums = std::move(mediums_started_successfully), - }; -} - -Status P2pClusterPcpHandler::StopDiscoveryImpl(ClientProxy* client) { - wifi_lan_medium_.StopDiscovery(client->GetDiscoveryServiceId()); - bluetooth_medium_.StopDiscovery(); - ble_medium_.StopScanning(client->GetDiscoveryServiceId()); - return {Status::kSuccess}; -} - -BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::ConnectImpl( - ClientProxy* client, BasePcpHandler::DiscoveredEndpoint* endpoint) { - if (!endpoint) { - return BasePcpHandler::ConnectImplResult{ - .status = {Status::kError}, - }; - } - switch (endpoint->medium) { - case proto::connections::Medium::BLUETOOTH: { - auto* bluetooth_endpoint = down_cast(endpoint); - if (bluetooth_endpoint) { - return BluetoothConnectImpl(client, bluetooth_endpoint); - } - break; - } - case proto::connections::Medium::BLE: { - auto* ble_endpoint = down_cast(endpoint); - if (ble_endpoint) { - return BleConnectImpl(client, ble_endpoint); - } - break; - } - case proto::connections::Medium::WIFI_LAN: { - auto* wifi_lan_endpoint = down_cast(endpoint); - if (wifi_lan_endpoint) { - return WifiLanConnectImpl(client, wifi_lan_endpoint); - } - break; - } - case proto::connections::Medium::WEB_RTC: { - auto* webrtc_endpoint = down_cast(endpoint); - if (webrtc_endpoint) { - return WebRtcConnectImpl(client, webrtc_endpoint); - } - break; - } - default: - break; - } - - return BasePcpHandler::ConnectImplResult{ - .status = {Status::kError}, - }; -} - -proto::connections::Medium P2pClusterPcpHandler::StartBluetoothAdvertising( - ClientProxy* client, const std::string& service_id, - const ByteArray& service_id_hash, const std::string& local_endpoint_id, - const ByteArray& local_endpoint_info, WebRtcState web_rtc_state) { - // Start listening for connections before advertising in case a connection - // request comes in very quickly. - NEARBY_LOG( - INFO, - "P2pClusterPcpHandler::StartBluetoothAdvertising: service=%s: start", - service_id.c_str()); - if (bluetooth_medium_.IsAcceptingConnections(service_id)) { - NEARBY_LOG(ERROR, "BT is already accepting connections for service=%s", - service_id.c_str()); - return proto::connections::UNKNOWN_MEDIUM; - } - - NEARBY_LOG( - INFO, - "P2pClusterPcpHandler::StartBluetoothAdvertising: service=%s: invoking", - service_id.c_str()); - if (!bluetooth_radio_.Enable() || - !bluetooth_medium_.StartAcceptingConnections( - service_id, {.accepted_cb = [this, client, local_endpoint_info]( - BluetoothSocket socket) { - if (!socket.IsValid()) { - NEARBY_LOG(ERROR, "Invalid socket in accept callback: name=%s", - std::string(local_endpoint_info).c_str()); - return; - } - RunOnPcpHandlerThread([this, client, local_endpoint_info, - socket = std::move(socket)]() mutable { - std::string remote_device_name = - socket.GetRemoteDevice().GetName(); - auto channel = absl::make_unique( - remote_device_name, socket); - ByteArray remote_device_info{remote_device_name}; - - OnIncomingConnection(client, remote_device_info, - std::move(channel), - proto::connections::Medium::BLUETOOTH); - }); - }})) { - NEARBY_LOG(ERROR, "BT failed to start accepting connections for service=%s", - service_id.c_str()); - return proto::connections::UNKNOWN_MEDIUM; - } - - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::StartBluetoothAdvertising: service=%s: " - "make name; id=%s, hash=%s, name=%s", - service_id.c_str(), local_endpoint_id.c_str(), - absl::BytesToHexString(service_id_hash.data()).c_str(), - absl::BytesToHexString(local_endpoint_info.data()).c_str()); - // Generate a BluetoothDeviceName with which to become Bluetooth discoverable. - // TODO(b/169550050): Implement UWBAddress. - std::string device_name(BluetoothDeviceName( - kBluetoothDeviceNameVersion, GetPcp(), local_endpoint_id, service_id_hash, - local_endpoint_info, ByteArray{}, web_rtc_state)); - if (device_name.empty()) { - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::StartBluetoothAdvertising: generate " - "BluetoothDeviceName failed"); - bluetooth_medium_.StopAcceptingConnections(service_id); - return proto::connections::UNKNOWN_MEDIUM; - } else { - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::StartBluetoothAdvertising: generate " - "BluetoothDeviceName succeeded; device_name=%s", - device_name.c_str()); - } - - NEARBY_LOG( - INFO, - "P2pClusterPcpHandler::StartBluetoothAdvertising: service=%s: come up", - service_id.c_str()); - // Become Bluetooth discoverable. - if (!bluetooth_medium_.TurnOnDiscoverability(device_name)) { - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::StartBluetoothAdvertising: failed to " - "turn on discoverability, device_name=%s", - device_name.c_str()); - bluetooth_medium_.StopAcceptingConnections(service_id); - return proto::connections::UNKNOWN_MEDIUM; - } else { - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::StartBluetoothAdvertising: succeeded to " - "turn on discoverability, device_name=%s", - device_name.c_str()); - } - NEARBY_LOG( - INFO, "P2pClusterPcpHandler::StartBluetoothAdvertising: service=%s: done", - service_id.c_str()); - return proto::connections::BLUETOOTH; -} - -proto::connections::Medium P2pClusterPcpHandler::StartBluetoothDiscovery( - BluetoothDiscoveredDeviceCallback callback, ClientProxy* client, - const std::string& service_id) { - if (bluetooth_radio_.Enable() && - bluetooth_medium_.StartDiscovery(std::move(callback))) { - NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartBluetoothDiscovery: ok"); - return proto::connections::BLUETOOTH; - } else { - NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartBluetoothDiscovery: failed"); - return proto::connections::UNKNOWN_MEDIUM; - } -} - -BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BluetoothConnectImpl( - ClientProxy* client, BluetoothEndpoint* endpoint) { - BluetoothDevice& device = endpoint->bluetooth_device; - - BluetoothSocket bluetooth_socket = - bluetooth_medium_.Connect(device, endpoint->service_id); - if (!bluetooth_socket.IsValid()) { - return BasePcpHandler::ConnectImplResult{ - .status = {Status::kBluetoothError}, - }; - } - - auto channel = absl::make_unique( - endpoint->endpoint_id, bluetooth_socket); - - return BasePcpHandler::ConnectImplResult{ - .medium = proto::connections::Medium::BLUETOOTH, - .status = {Status::kSuccess}, - .endpoint_channel = std::move(channel), - }; -} - -proto::connections::Medium P2pClusterPcpHandler::StartBleAdvertising( - ClientProxy* client, const std::string& service_id, - const std::string& local_endpoint_id, const ByteArray& local_endpoint_info, - const ConnectionOptions& options, WebRtcState web_rtc_state) { - bool fast_advertisement = !options.fast_advertisement_service_uuid.empty(); - PowerLevel power_level = - options.low_power ? PowerLevel::kLowPower : PowerLevel::kHighPower; - - // Start listening for connections before advertising in case a connection - // request comes in very quickly. BLE allows connecting over BLE itself, as - // well as advertising the Bluetooth MAC address to allow connecting over - // Bluetooth Classic. - NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleAdvertising: service_id=" - << service_id << ": start"; - if (!ble_medium_.IsAcceptingConnections(service_id)) { - if (!bluetooth_radio_.Enable() || - !ble_medium_.StartAcceptingConnections( - service_id, {.accepted_cb = [this, client, local_endpoint_info]( - BleSocket socket, - const std::string& service_id) { - if (!socket.IsValid()) { - NEARBY_LOG(ERROR, "Invalid socket in accept callback: name=%s", - std::string(local_endpoint_info).c_str()); - return; - } - RunOnPcpHandlerThread([this, client, local_endpoint_info, - service_id, - socket = std::move(socket)]() mutable { - std::string remote_peripheral_name = - socket.GetRemotePeripheral().GetName(); - auto channel = absl::make_unique( - remote_peripheral_name, socket); - ByteArray remote_peripheral_info = - socket.GetRemotePeripheral().GetAdvertisementBytes( - service_id); - - OnIncomingConnection(client, remote_peripheral_info, - std::move(channel), - proto::connections::Medium::BLE); - }); - }})) { - NEARBY_LOGS(ERROR) - << "Ble failed to start accepting connections for service_id=" - << service_id; - return proto::connections::UNKNOWN_MEDIUM; - } - NEARBY_LOGS(ERROR) - << "Ble succeed to start accepting connections for service_id=" - << service_id; - } - - if (ShouldAdvertiseBluetoothMacOverBle(power_level) || - ShouldAcceptBluetoothConnections(options)) { - if (bluetooth_medium_.IsAvailable() && - !bluetooth_medium_.IsAcceptingConnections(service_id)) { - if (!bluetooth_radio_.Enable() || - !bluetooth_medium_.StartAcceptingConnections( - service_id, {.accepted_cb = [this, client, local_endpoint_info]( - BluetoothSocket socket) { - if (!socket.IsValid()) { - NEARBY_LOG(ERROR, - "Invalid socket in accept callback: name=%s", - std::string(local_endpoint_info).c_str()); - return; - } - RunOnPcpHandlerThread([this, client, local_endpoint_info, - socket = std::move(socket)]() mutable { - std::string remote_device_name = - socket.GetRemoteDevice().GetName(); - auto channel = absl::make_unique( - remote_device_name, socket); - ByteArray remote_device_info{remote_device_name}; - - OnIncomingConnection(client, remote_device_info, - std::move(channel), - proto::connections::Medium::BLUETOOTH); - }); - }})) { - NEARBY_LOGS(ERROR) - << "BT failed to start accepting connections for service_id=" - << service_id; - ble_medium_.StopAcceptingConnections(service_id); - return proto::connections::UNKNOWN_MEDIUM; - } - NEARBY_LOGS(ERROR) - << "BT succeed to start accepting connections for service_id=" - << service_id; - } - } - - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::StartBleAdvertising: service=%s: " - "make advertisement; id=%s, name=%s", - service_id.c_str(), local_endpoint_id.c_str(), - std::string(local_endpoint_info).c_str()); - // Generate a BleAdvertisement. If a fast advertisement service UUID was - // provided, create a fast BleAdvertisement. - ByteArray advertisement_bytes; - // TODO(b/169550050): Implement UWBAddress. - if (fast_advertisement) { - advertisement_bytes = ByteArray( - BleAdvertisement(kBleAdvertisementVersion, GetPcp(), local_endpoint_id, - local_endpoint_info, ByteArray{})); - } else { - const ByteArray service_id_hash = - GenerateHash(service_id, BleAdvertisement::kServiceIdHashLength); - std::string bluetooth_mac_address; - if (bluetooth_medium_.IsAvailable() && - ShouldAdvertiseBluetoothMacOverBle(power_level)) - bluetooth_mac_address = bluetooth_medium_.GetMacAddress(); - - advertisement_bytes = ByteArray( - BleAdvertisement(kBleAdvertisementVersion, GetPcp(), service_id_hash, - local_endpoint_id, local_endpoint_info, - bluetooth_mac_address, ByteArray{}, web_rtc_state)); - } - if (advertisement_bytes.Empty()) { - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::StartBleAdvertising: generate " - "BleAdvertisement failed"); - ble_medium_.StopAcceptingConnections(service_id); - return proto::connections::UNKNOWN_MEDIUM; - } else { - NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleAdvertising: generate " - "BleAdvertisement succeeded; advertisement_bytes=" - << advertisement_bytes.data(); - } - - NEARBY_LOG( - INFO, "P2pClusterPcpHandler::StartBleAdvertising: service_id=%s: come up", - service_id.c_str()); - - if (!ble_medium_.StartAdvertising(service_id, advertisement_bytes, - options.fast_advertisement_service_uuid)) { - NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleAdvertising: failed to " - "start advertising, advertisement_bytes=%p" - << advertisement_bytes.data(); - ble_medium_.StopAcceptingConnections(service_id); - return proto::connections::UNKNOWN_MEDIUM; - } - NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleAdvertising: service_id=" - << service_id << ": done"; - return proto::connections::BLE; -} - -proto::connections::Medium P2pClusterPcpHandler::StartBleScanning( - BleDiscoveredPeripheralCallback callback, ClientProxy* client, - const std::string& service_id, - const std::string& fast_advertisement_service_uuid) { - if (bluetooth_radio_.Enable() && - ble_medium_.StartScanning(service_id, fast_advertisement_service_uuid, - std::move(callback))) { - NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleScanning: ok"; - return proto::connections::BLE; - } else { - NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleScanning: failed"; - return proto::connections::UNKNOWN_MEDIUM; - } -} - -BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BleConnectImpl( - ClientProxy* client, BleEndpoint* endpoint) { - BlePeripheral& peripheral = endpoint->ble_peripheral; - - BleSocket ble_socket = ble_medium_.Connect(peripheral, endpoint->service_id); - if (!ble_socket.IsValid()) { - return BasePcpHandler::ConnectImplResult{ - .status = {Status::kBleError}, - }; - } - - auto channel = - absl::make_unique(endpoint->endpoint_id, ble_socket); - - return BasePcpHandler::ConnectImplResult{ - .medium = proto::connections::Medium::BLE, - .status = {Status::kSuccess}, - .endpoint_channel = std::move(channel), - }; -} - -proto::connections::Medium P2pClusterPcpHandler::StartWifiLanAdvertising( - ClientProxy* client, const std::string& service_id, - const ByteArray& service_id_hash, const std::string& local_endpoint_id, - const ByteArray& local_endpoint_info, WebRtcState web_rtc_state) { - // Start listening for connections before advertising in case a connection - // request comes in very quickly. - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::StartWifiLanAdvertising: service=%s: start", - service_id.c_str()); - if (wifi_lan_medium_.IsAcceptingConnections(service_id)) { - NEARBY_LOG(ERROR, "WifiLan is already accepting connections for service=%s", - service_id.c_str()); - return proto::connections::UNKNOWN_MEDIUM; - } - - NEARBY_LOG( - INFO, - "P2pClusterPcpHandler::StartWifiLanAdvertising: service=%s: invoking", - service_id.c_str()); - if (!wifi_lan_medium_.StartAcceptingConnections( - service_id, {.accepted_cb = [this, client, local_endpoint_info]( - WifiLanSocket socket, - const std::string& service_id) { - if (!socket.IsValid()) { - NEARBY_LOG(ERROR, "Invalid socket in accept callback: name=%s", - std::string(local_endpoint_info).c_str()); - return; - } - RunOnPcpHandlerThread([this, client, local_endpoint_info, - socket = std::move(socket)]() mutable { - std::string remote_service_info_name = - socket.GetRemoteWifiLanService().GetName(); - auto channel = absl::make_unique( - remote_service_info_name, socket); - ByteArray remote_service_info{remote_service_info_name}; - - OnIncomingConnection(client, remote_service_info, - std::move(channel), - proto::connections::Medium::WIFI_LAN); - }); - }})) { - NEARBY_LOG(ERROR, - "WifiLan failed to start accepting connections for service=%s", - service_id.c_str()); - return proto::connections::UNKNOWN_MEDIUM; - } - - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::StartWifiLanAdvertising: service=%s: " - "make name; id=%s, hash=%s, name=%s", - service_id.c_str(), local_endpoint_id.c_str(), - absl::BytesToHexString(service_id_hash.data()).c_str(), - absl::BytesToHexString(local_endpoint_info.data()).c_str()); - // Generate a WifiLanServiceInfo with which to become WifiLan discoverable. - // TODO(b/169550050): Implement UWBAddress. - std::string service_info_name(WifiLanServiceInfo( - kWifiLanServiceInfoVersion, GetPcp(), local_endpoint_id, service_id_hash, - local_endpoint_info, ByteArray{}, web_rtc_state)); - if (service_info_name.empty()) { - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::StartWifiLanAdvertising: generate " - "WifiLanServiceInfo failed"); - wifi_lan_medium_.StopAcceptingConnections(service_id); - return proto::connections::UNKNOWN_MEDIUM; - } else { - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::StartWifiLanAdvertising: generate " - "WifiLanServiceInfo succeeded; service_info_name=%s", - service_info_name.c_str()); - } - - NEARBY_LOG( - INFO, - "P2pClusterPcpHandler::StartWifiLanAdvertising: service=%s: come up", - service_id.c_str()); - - if (!wifi_lan_medium_.StartAdvertising(service_id, service_info_name)) { - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::StartWifiLanAdvertising: failed to " - "start advertising, service_info_name=%s", - service_info_name.c_str()); - wifi_lan_medium_.StopAcceptingConnections(service_id); - return proto::connections::UNKNOWN_MEDIUM; - } - NEARBY_LOG(INFO, - "P2pClusterPcpHandler::StartWifiLanAdvertising: service=%s: done", - service_id.c_str()); - return proto::connections::WIFI_LAN; -} - -proto::connections::Medium P2pClusterPcpHandler::StartWifiLanDiscovery( - WifiLanDiscoveredServiceCallback callback, ClientProxy* client, - const std::string& service_id) { - if (wifi_lan_medium_.StartDiscovery(service_id, std::move(callback))) { - NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartWifiLanDiscovery: ok"); - return proto::connections::WIFI_LAN; - } else { - NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartWifiLanDiscovery: failed"); - return proto::connections::UNKNOWN_MEDIUM; - } -} - -BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::WifiLanConnectImpl( - ClientProxy* client, WifiLanEndpoint* endpoint) { - WifiLanService& service = endpoint->wifi_lan_service; - - WifiLanSocket wifi_lan_socket = - wifi_lan_medium_.Connect(service, endpoint->service_id); - if (!wifi_lan_socket.IsValid()) { - return BasePcpHandler::ConnectImplResult{ - .status = {Status::kWifiLanError}, - }; - } - - auto channel = absl::make_unique( - endpoint->endpoint_id, wifi_lan_socket); - - return BasePcpHandler::ConnectImplResult{ - .medium = proto::connections::Medium::WIFI_LAN, - .status = {Status::kSuccess}, - .endpoint_channel = std::move(channel), - }; -} - -proto::connections::Medium -P2pClusterPcpHandler::StartListeningForWebRtcConnections( - ClientProxy* client, const string& service_id, - const string& local_endpoint_id, const ByteArray& local_endpoint_info) { - if (!webrtc_medium_.IsAvailable()) { - return proto::connections::UNKNOWN_MEDIUM; - } - - if (!webrtc_medium_.IsAcceptingConnections()) { - mediums::PeerId self_id = CreatePeerIdFromAdvertisement( - service_id, local_endpoint_id, local_endpoint_info); - if (!webrtc_medium_.StartAcceptingConnections( - self_id, {[this, client, local_endpoint_info]( - mediums::WebRtcSocketWrapper socket) { - if (!socket.IsValid()) { - NEARBY_LOG(ERROR, "Invalid socket in accept callback: name=%s", - std::string(local_endpoint_info).c_str()); - return; - } - - RunOnPcpHandlerThread( - [this, client, socket = std::move(socket)]() { - string remote_device_name = "WebRtcSocket"; - auto channel = absl::make_unique( - remote_device_name, socket); - ByteArray remote_device_info{remote_device_name}; - - OnIncomingConnection(client, remote_device_info, - std::move(channel), - proto::connections::WEB_RTC); - }); - }})) { - return proto::connections::UNKNOWN_MEDIUM; - } - } - - return proto::connections::WEB_RTC; -} - -BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::WebRtcConnectImpl( - ClientProxy* client, WebRtcEndpoint* webrtc_endpoint) { - mediums::WebRtcSocketWrapper socket_wrapper = - webrtc_medium_.Connect(webrtc_endpoint->peer_id); - - if (!socket_wrapper.IsValid()) { - return BasePcpHandler::ConnectImplResult{.status = {Status::kError}}; - } - - auto channel = absl::make_unique( - webrtc_endpoint->endpoint_id, socket_wrapper); - - if (!channel) { - socket_wrapper.Close(); - return BasePcpHandler::ConnectImplResult{.status = {Status::kError}}; - } - - return BasePcpHandler::ConnectImplResult{ - .medium = proto::connections::Medium::WEB_RTC, - .status = {Status::kSuccess}, - .endpoint_channel = std::move(channel)}; -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/p2p_cluster_pcp_handler.h b/cpp/core_v2/internal/p2p_cluster_pcp_handler.h deleted file mode 100644 index 26fc6464..00000000 --- a/cpp/core_v2/internal/p2p_cluster_pcp_handler.h +++ /dev/null @@ -1,208 +0,0 @@ -#ifndef CORE_V2_INTERNAL_P2P_CLUSTER_PCP_HANDLER_H_ -#define CORE_V2_INTERNAL_P2P_CLUSTER_PCP_HANDLER_H_ - -#include -#include - -#include "core_v2/internal/base_pcp_handler.h" -#include "core_v2/internal/ble_advertisement.h" -#include "core_v2/internal/bluetooth_device_name.h" -#include "core_v2/internal/bwu_manager.h" -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/endpoint_channel_manager.h" -#include "core_v2/internal/endpoint_manager.h" -#include "core_v2/internal/mediums/bluetooth_classic.h" -#include "core_v2/internal/mediums/mediums.h" -#include "core_v2/internal/mediums/webrtc.h" -#include "core_v2/internal/mediums/webrtc/peer_id.h" -#include "core_v2/internal/pcp.h" -#include "core_v2/internal/wifi_lan_service_info.h" -#include "core_v2/options.h" -#include "core_v2/strategy.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/public/bluetooth_classic.h" -#include "platform_v2/public/wifi_lan.h" -#include "proto/connections_enums.pb.h" - -namespace location { -namespace nearby { -namespace connections { - -// Concrete implementation of the PCPHandler for the P2P_CLUSTER PCP. This PCP -// is reserved for mediums that can connect to multiple devices simultaneously -// and all devices are considered equal. For asymmetric mediums, where one -// device is a server and the others are clients, use P2PStarPCPHandler instead. -// -// Currently, this implementation advertises/discovers over Bluetooth and -// connects over Bluetooth. -class P2pClusterPcpHandler : public BasePcpHandler { - public: - P2pClusterPcpHandler(Mediums* mediums, EndpointManager* endpoint_manager, - EndpointChannelManager* channel_manager, - BwuManager* bwu_manager, - Pcp pcp = Pcp::kP2pCluster); - ~P2pClusterPcpHandler() override = default; - - protected: - std::vector GetConnectionMediumsByPriority() - override; - proto::connections::Medium GetDefaultUpgradeMedium() override; - - // @PCPHandlerThread - BasePcpHandler::StartOperationResult StartAdvertisingImpl( - ClientProxy* client, const std::string& service_id, - const std::string& local_endpoint_id, - const ByteArray& local_endpoint_info, - const ConnectionOptions& options) override; - - // @PCPHandlerThread - Status StopAdvertisingImpl(ClientProxy* client) override; - - // @PCPHandlerThread - BasePcpHandler::StartOperationResult StartDiscoveryImpl( - ClientProxy* client, const std::string& service_id, - const ConnectionOptions& options) override; - - // @PCPHandlerThread - Status StopDiscoveryImpl(ClientProxy* client) override; - - // @PCPHandlerThread - BasePcpHandler::ConnectImplResult ConnectImpl( - ClientProxy* client, - BasePcpHandler::DiscoveredEndpoint* endpoint) override; - - private: - struct BluetoothEndpoint : public BasePcpHandler::DiscoveredEndpoint { - BluetoothEndpoint(DiscoveredEndpoint endpoint, BluetoothDevice device) - : DiscoveredEndpoint(std::move(endpoint)), - bluetooth_device(std::move(device)) {} - - BluetoothDevice bluetooth_device; - }; - struct BleEndpoint : public BasePcpHandler::DiscoveredEndpoint { - BleEndpoint(DiscoveredEndpoint endpoint, BlePeripheral peripheral) - : DiscoveredEndpoint(std::move(endpoint)), - ble_peripheral(std::move(peripheral)) {} - BlePeripheral ble_peripheral; - }; - - // Holds the state required to re-create a BleEndpoint we see on a - // BlePeripheral, so BlePeripheralLostHandler can call - // BasePcpHandler::OnEndpointLost() with the same information as was passed - // in to BasePCPHandler::onEndpointFound(). - struct BleEndpointState { - public: - BleEndpointState(const string& endpoint_id, const ByteArray& endpoint_info) - : endpoint_id(endpoint_id), endpoint_info(endpoint_info) {} - - std::string endpoint_id; - ByteArray endpoint_info; - }; - struct WifiLanEndpoint : public BasePcpHandler::DiscoveredEndpoint { - WifiLanEndpoint(DiscoveredEndpoint endpoint, WifiLanService service) - : DiscoveredEndpoint(std::move(endpoint)), - wifi_lan_service(std::move(service)) {} - - WifiLanService wifi_lan_service; - }; - - using BluetoothDiscoveredDeviceCallback = - BluetoothClassic::DiscoveredDeviceCallback; - using BleDiscoveredPeripheralCallback = Ble::DiscoveredPeripheralCallback; - using WifiLanDiscoveredServiceCallback = WifiLan::DiscoveredServiceCallback; - - static constexpr BluetoothDeviceName::Version kBluetoothDeviceNameVersion = - BluetoothDeviceName::Version::kV1; - static constexpr BleAdvertisement::Version kBleAdvertisementVersion = - BleAdvertisement::Version::kV1; - static constexpr WifiLanServiceInfo::Version kWifiLanServiceInfoVersion = - WifiLanServiceInfo::Version::kV1; - - static ByteArray GenerateHash(const std::string& source, size_t size); - static bool ShouldAdvertiseBluetoothMacOverBle(PowerLevel power_level); - static bool ShouldAcceptBluetoothConnections( - const ConnectionOptions& options); - - // Bluetooth - bool IsRecognizedBluetoothEndpoint(const std::string& name_string, - const std::string& service_id, - const BluetoothDeviceName& name) const; - void BluetoothDeviceDiscoveredHandler(ClientProxy* client, - const std::string& service_id, - BluetoothDevice& device); - void BluetoothDeviceLostHandler(ClientProxy* client, - const std::string& service_id, - BluetoothDevice& device); - proto::connections::Medium StartBluetoothAdvertising( - ClientProxy* client, const std::string& service_id, - const ByteArray& service_id_hash, const std::string& local_endpoint_id, - const ByteArray& local_endpoint_info, WebRtcState web_rtc_state); - proto::connections::Medium StartBluetoothDiscovery( - BluetoothDiscoveredDeviceCallback callback, ClientProxy* client, - const std::string& service_id); - BasePcpHandler::ConnectImplResult BluetoothConnectImpl( - ClientProxy* client, BluetoothEndpoint* endpoint); - - // Ble - // Maps a BlePeripheral to its corresponding BleEndpointState. - absl::flat_hash_map found_ble_endpoints_; - bool IsRecognizedBleEndpoint(const std::string& service_id, - const BleAdvertisement& advertisement) const; - void BlePeripheralDiscoveredHandler(ClientProxy* client, - BlePeripheral& peripheral, - const std::string& service_id, - const ByteArray& advertisement_bytes, - bool fast_advertisement); - void BlePeripheralLostHandler(ClientProxy* client, BlePeripheral& peripheral, - const std::string& service_id); - proto::connections::Medium StartBleAdvertising( - ClientProxy* client, const std::string& service_id, - const std::string& local_endpoint_id, - const ByteArray& local_endpoint_info, const ConnectionOptions& options, - WebRtcState web_rtc_state); - proto::connections::Medium StartBleScanning( - BleDiscoveredPeripheralCallback callback, ClientProxy* client, - const std::string& service_id, - const std::string& fast_advertisement_service_uuid); - BasePcpHandler::ConnectImplResult BleConnectImpl(ClientProxy* client, - BleEndpoint* endpoint); - - // WifiLan - bool IsRecognizedWifiLanEndpoint( - const std::string& service_id, - const WifiLanServiceInfo& service_info) const; - void WifiLanServiceDiscoveredHandler(ClientProxy* client, - WifiLanService& service, - const std::string& service_id); - void WifiLanServiceLostHandler(ClientProxy* client, WifiLanService& service, - const std::string& service_id); - proto::connections::Medium StartWifiLanAdvertising( - ClientProxy* client, const std::string& service_id, - const ByteArray& service_id_hash, const std::string& local_endpoint_id, - const ByteArray& local_endpoint_info, WebRtcState web_rtc_state); - proto::connections::Medium StartWifiLanDiscovery( - WifiLanDiscoveredServiceCallback callback, ClientProxy* client, - const std::string& service_id); - BasePcpHandler::ConnectImplResult WifiLanConnectImpl( - ClientProxy* client, WifiLanEndpoint* endpoint); - - // WebRtc - proto::connections::Medium StartListeningForWebRtcConnections( - ClientProxy* client, const std::string& service_id, - const std::string& local_endpoint_id, - const ByteArray& local_endpoint_info); - BasePcpHandler::ConnectImplResult WebRtcConnectImpl( - ClientProxy* client, WebRtcEndpoint* webrtc_endpoint); - - BluetoothRadio& bluetooth_radio_; - BluetoothClassic& bluetooth_medium_; - Ble& ble_medium_; - WifiLan& wifi_lan_medium_; - mediums::WebRtc& webrtc_medium_; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_P2P_CLUSTER_PCP_HANDLER_H_ diff --git a/cpp/core_v2/internal/p2p_point_to_point_pcp_handler.cc b/cpp/core_v2/internal/p2p_point_to_point_pcp_handler.cc deleted file mode 100644 index 64e05d4a..00000000 --- a/cpp/core_v2/internal/p2p_point_to_point_pcp_handler.cc +++ /dev/null @@ -1,49 +0,0 @@ -#include "core_v2/internal/p2p_point_to_point_pcp_handler.h" - -namespace location { -namespace nearby { -namespace connections { - -P2pPointToPointPcpHandler::P2pPointToPointPcpHandler( - Mediums& mediums, EndpointManager& endpoint_manager, - EndpointChannelManager& channel_manager, BwuManager& bwu_manager, Pcp pcp) - : P2pStarPcpHandler(mediums, endpoint_manager, channel_manager, bwu_manager, - pcp) {} - -std::vector -P2pPointToPointPcpHandler::GetConnectionMediumsByPriority() { - std::vector mediums; - if (mediums_->GetWifiLan().IsAvailable()) { - mediums.push_back(proto::connections::WIFI_LAN); - } - if (mediums_->GetWebRtc().IsAvailable()) { - mediums.push_back(proto::connections::WEB_RTC); - } - if (mediums_->GetBluetoothClassic().IsAvailable()) { - mediums.push_back(proto::connections::BLUETOOTH); - } - if (mediums_->GetBle().IsAvailable()) { - mediums.push_back(proto::connections::BLE); - } - return mediums; -} - -bool P2pPointToPointPcpHandler::CanSendOutgoingConnection( - ClientProxy* client) const { - // For point to point, we can only send an outgoing connection while we have - // no other connections. - return !this->HasOutgoingConnections(client) && - !this->HasIncomingConnections(client); -} - -bool P2pPointToPointPcpHandler::CanReceiveIncomingConnection( - ClientProxy* client) const { - // For point to point, we can only receive an incoming connection while we - // have no other connections. - return !this->HasOutgoingConnections(client) && - !this->HasIncomingConnections(client); -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/p2p_point_to_point_pcp_handler.h b/cpp/core_v2/internal/p2p_point_to_point_pcp_handler.h deleted file mode 100644 index 4b09ab3c..00000000 --- a/cpp/core_v2/internal/p2p_point_to_point_pcp_handler.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef CORE_V2_INTERNAL_P2P_POINT_TO_POINT_PCP_HANDLER_H_ -#define CORE_V2_INTERNAL_P2P_POINT_TO_POINT_PCP_HANDLER_H_ - -#include "core_v2/internal/endpoint_channel_manager.h" -#include "core_v2/internal/endpoint_manager.h" -#include "core_v2/internal/p2p_star_pcp_handler.h" -#include "core_v2/internal/pcp.h" -#include "core_v2/strategy.h" - -namespace location { -namespace nearby { -namespace connections { - -// Concrete implementation of the PCPHandler for the P2P_POINT_TO_POINT. This -// PCP is for mediums that have limitations on the number of simultaneous -// connections; all mediums in P2P_STAR are valid for P2P_POINT_TO_POINT, but -// not all mediums in P2P_POINT_TO_POINT are valid for P2P_STAR. -// -// Currently, this implementation advertises/discovers over Bluetooth -// and connects over Bluetooth. -class P2pPointToPointPcpHandler : public P2pStarPcpHandler { - public: - P2pPointToPointPcpHandler(Mediums& mediums, EndpointManager& endpoint_manager, - EndpointChannelManager& channel_manager, - BwuManager& bwu_manager, - Pcp pcp = Pcp::kP2pPointToPoint); - - protected: - std::vector GetConnectionMediumsByPriority() - override; - - bool CanSendOutgoingConnection(ClientProxy* client) const override; - bool CanReceiveIncomingConnection(ClientProxy* client) const override; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_P2P_POINT_TO_POINT_PCP_HANDLER_H_ diff --git a/cpp/core_v2/internal/p2p_star_pcp_handler.cc b/cpp/core_v2/internal/p2p_star_pcp_handler.cc deleted file mode 100644 index 80e773cd..00000000 --- a/cpp/core_v2/internal/p2p_star_pcp_handler.cc +++ /dev/null @@ -1,54 +0,0 @@ -#include "core_v2/internal/p2p_star_pcp_handler.h" - -#include - -namespace location { -namespace nearby { -namespace connections { - -P2pStarPcpHandler::P2pStarPcpHandler(Mediums& mediums, - EndpointManager& endpoint_manager, - EndpointChannelManager& channel_manager, - BwuManager& bwu_manager, Pcp pcp) - : P2pClusterPcpHandler(&mediums, &endpoint_manager, &channel_manager, - &bwu_manager, pcp) {} - -std::vector -P2pStarPcpHandler::GetConnectionMediumsByPriority() { - std::vector mediums; - if (mediums_->GetWifiLan().IsAvailable()) { - mediums.push_back(proto::connections::WIFI_LAN); - } - if (mediums_->GetWebRtc().IsAvailable()) { - mediums.push_back(proto::connections::WEB_RTC); - } - if (mediums_->GetBluetoothClassic().IsAvailable()) { - mediums.push_back(proto::connections::BLUETOOTH); - } - if (mediums_->GetBle().IsAvailable()) { - mediums.push_back(proto::connections::BLE); - } - return mediums; -} - -proto::connections::Medium P2pStarPcpHandler::GetDefaultUpgradeMedium() { - return proto::connections::Medium::WIFI_HOTSPOT; -} - -bool P2pStarPcpHandler::CanSendOutgoingConnection(ClientProxy* client) const { - // For star, we can only send an outgoing connection while we have no other - // connections. - return !this->HasOutgoingConnections(client) && - !this->HasIncomingConnections(client); -} - -bool P2pStarPcpHandler::CanReceiveIncomingConnection( - ClientProxy* client) const { - // For star, we can only receive an incoming connection if we've sent no - // outgoing connections. - return !this->HasOutgoingConnections(client); -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/p2p_star_pcp_handler.h b/cpp/core_v2/internal/p2p_star_pcp_handler.h deleted file mode 100644 index c1418ffd..00000000 --- a/cpp/core_v2/internal/p2p_star_pcp_handler.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef CORE_V2_INTERNAL_P2P_STAR_PCP_HANDLER_H_ -#define CORE_V2_INTERNAL_P2P_STAR_PCP_HANDLER_H_ - -#include - -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/endpoint_channel_manager.h" -#include "core_v2/internal/endpoint_manager.h" -#include "core_v2/internal/p2p_cluster_pcp_handler.h" -#include "core_v2/internal/pcp.h" -#include "core_v2/strategy.h" - -namespace location { -namespace nearby { -namespace connections { - -// Concrete implementation of the PcpHandler for the P2P_STAR PCP. This Pcp is -// for mediums that have one server with (potentially) many clients; all mediums -// in P2P_CLUSTER are valid for P2P_STAR, but not all mediums in P2P_STAR are -// valid for P2P_CLUSTER. -// -// Currently, this implementation advertises/discovers over Bluetooth -// and connects over Bluetooth. -class P2pStarPcpHandler : public P2pClusterPcpHandler { - public: - P2pStarPcpHandler(Mediums& mediums, EndpointManager& endpoint_manager, - EndpointChannelManager& channel_manager, - BwuManager& bwu_manager, - Pcp pcp = Pcp::kP2pStar); - - protected: - std::vector GetConnectionMediumsByPriority() - override; - proto::connections::Medium GetDefaultUpgradeMedium() override; - - bool CanSendOutgoingConnection(ClientProxy* client) const override; - bool CanReceiveIncomingConnection(ClientProxy* client) const override; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_P2P_STAR_PCP_HANDLER_H_ diff --git a/cpp/core_v2/internal/payload_manager.cc b/cpp/core_v2/internal/payload_manager.cc deleted file mode 100644 index 27b51a0a..00000000 --- a/cpp/core_v2/internal/payload_manager.cc +++ /dev/null @@ -1,1070 +0,0 @@ -#include "core_v2/internal/payload_manager.h" - -#include -#include -#include -#include -#include - -#include "core_v2/internal/internal_payload_factory.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/mutex_lock.h" -#include "platform_v2/public/single_thread_executor.h" -#include "platform_v2/public/system_clock.h" -#include "absl/memory/memory.h" -#include "absl/strings/str_cat.h" -#include "absl/time/time.h" - -namespace location { -namespace nearby { -namespace connections { - -// C++14 requires to declare this. -// TODO(apolyudov): remove when migration to c++17 is possible. -constexpr const absl::Duration PayloadManager::kWaitCloseTimeout; - -bool PayloadManager::SendPayloadLoop( - ClientProxy* client, PendingPayload& pending_payload, - PayloadTransferFrame::PayloadHeader& payload_header, - std::int64_t& next_chunk_offset) { - // in lieu of structured binding: - auto pair = GetAvailableAndUnavailableEndpoints(pending_payload); - const EndpointIds& available_endpoint_ids = - EndpointsToEndpointIds(pair.first); - const Endpoints& unavailable_endpoints = pair.second; - - NEARBY_LOG(INFO, - "SendPayloadLoop: Available: { %s }; Unavailable: { %s }; " - "payload_id=%" PRIX64 "; self=%p", - ToString(available_endpoint_ids).c_str(), - ToString(unavailable_endpoints).c_str(), - static_cast(payload_header.id()), this); - - // First, handle any non-available endpoints. - for (const auto& endpoint : unavailable_endpoints) { - HandleFinishedOutgoingPayload( - client, {endpoint->id}, payload_header, next_chunk_offset, - EndpointInfoStatusToPayloadStatus(endpoint->status.Get())); - } - - // Update the still-active recipients of this payload. - if (available_endpoint_ids.empty()) { - NEARBY_LOG(INFO, "No more available endpoints: payload_id=%" PRIX64, - pending_payload.GetInternalPayload()->GetId()); - return false; - } - - // Check if the payload has been cancelled by the client and, if so, - // notify the remaining recipients. - if (pending_payload.IsLocallyCanceled()) { - NEARBY_LOG(INFO, "Payload canceled locally: payload_id=%" PRIX64, - pending_payload.GetInternalPayload()->GetId()); - HandleFinishedOutgoingPayload( - client, available_endpoint_ids, payload_header, next_chunk_offset, - proto::connections::PayloadStatus::LOCAL_CANCELLATION); - return false; - } - - // Update the current offsets for all endpoints still active for this - // payload. For the sake of accuracy, we update the pending payload here - // because it's after all payload terminating events are handled, but - // right before we actually start detaching the next chunk. - for (const auto& endpoint_id : available_endpoint_ids) { - pending_payload.SetOffsetForEndpoint(endpoint_id, next_chunk_offset); - } - - // This will block if there is no data to transfer. - // It will resume when new data arrives, or if Close() is called. - ByteArray next_chunk = - pending_payload.GetInternalPayload()->DetachNextChunk(); - if (shutdown_.Get()) return false; - // Save chunk size. We'll need it after we move next_chunk. - auto next_chunk_size = next_chunk.size(); - if (!next_chunk_size && - pending_payload.GetInternalPayload()->GetTotalSize() > 0 && - pending_payload.GetInternalPayload()->GetTotalSize() < - next_chunk_offset) { - NEARBY_LOG(INFO, "Payload xfer failed: payload_id=%" PRIX64, - pending_payload.GetInternalPayload()->GetId()); - HandleFinishedOutgoingPayload( - client, available_endpoint_ids, payload_header, next_chunk_offset, - proto::connections::PayloadStatus::LOCAL_ERROR); - return false; - } - - PayloadTransferFrame::PayloadChunk payload_chunk( - CreatePayloadChunk(next_chunk_offset, std::move(next_chunk))); - const EndpointIds& failed_endpoint_ids = endpoint_manager_->SendPayloadChunk( - payload_header, payload_chunk, available_endpoint_ids); - // Check whether at least one endpoint failed. - if (!failed_endpoint_ids.empty()) { - NEARBY_LOG(INFO, - "Payload xfer: endpoints failed: payload_id=%" PRIX64 - "; ids={%s}", - static_cast(payload_header.id()), - ToString(failed_endpoint_ids).c_str()); - HandleFinishedOutgoingPayload( - client, failed_endpoint_ids, payload_header, next_chunk_offset, - proto::connections::PayloadStatus::ENDPOINT_IO_ERROR); - } - - // Check whether at least one endpoint succeeded -- if they all failed, - // we'll just go right back to the top of the loop and break out when - // availableEndpointIds is re-synced and found to be empty at that point. - if (failed_endpoint_ids.size() < available_endpoint_ids.size()) { - for (const auto& endpoint_id : available_endpoint_ids) { - if (std::find(failed_endpoint_ids.begin(), failed_endpoint_ids.end(), - endpoint_id) == failed_endpoint_ids.end()) { - HandleSuccessfulOutgoingChunk( - client, endpoint_id, payload_header, payload_chunk.flags(), - payload_chunk.offset(), payload_chunk.body().size()); - } - } - - next_chunk_offset += next_chunk_size; - - if (!next_chunk_size) { - // That was the last chunk, we're outta here. - NEARBY_LOG( - INFO, "Payload xfer done: payload_id=%" PRIX64 "; size=%" PRId64, - pending_payload.GetInternalPayload()->GetId(), next_chunk_offset); - return false; - } - } - - return true; -} - -std::pair -PayloadManager::GetAvailableAndUnavailableEndpoints( - const PendingPayload& pending_payload) { - Endpoints available; - Endpoints unavailable; - for (auto* endpoint_info : pending_payload.GetEndpoints()) { - NEARBY_LOG(INFO, "EndpointInfo: %p; id=%s; status=%d", endpoint_info, - endpoint_info->id.c_str(), endpoint_info->status.Get()); - if (endpoint_info->status.Get() == - PayloadManager::EndpointInfo::Status::kAvailable) { - available.push_back(endpoint_info); - } else { - unavailable.push_back(endpoint_info); - } - } - return std::make_pair(std::move(available), std::move(unavailable)); -} - -PayloadManager::EndpointIds PayloadManager::EndpointsToEndpointIds( - const Endpoints& endpoints) { - EndpointIds endpoint_ids; - endpoint_ids.reserve(endpoints.size()); - for (const auto& item : endpoints) { - if (item) { - endpoint_ids.emplace_back(item->id); - } - } - return endpoint_ids; -} - -std::string PayloadManager::ToString(const Endpoints& endpoints) { - std::string endpoints_string = absl::StrCat(endpoints.size(), ": "); - bool first = true; - for (const auto& item : endpoints) { - if (first) { - absl::StrAppend(&endpoints_string, item->id); - first = false; - } else { - absl::StrAppend(&endpoints_string, ", ", item->id); - } - } - return endpoints_string; -} - -std::string PayloadManager::ToString(const EndpointIds& endpoint_ids) { - std::string endpoints_string = absl::StrCat(endpoint_ids.size(), ": "); - bool first = true; - for (const auto& id : endpoint_ids) { - if (first) { - absl::StrAppend(&endpoints_string, id); - first = false; - } else { - absl::StrAppend(&endpoints_string, ", ", id); - } - } - return endpoints_string; -} - -// Creates and starts tracking a PendingPayload for this Payload. -Payload::Id PayloadManager::CreateOutgoingPayload( - Payload payload, const EndpointIds& endpoint_ids) { - auto internal_payload{CreateOutgoingInternalPayload(std::move(payload))}; - Payload::Id payload_id = internal_payload->GetId(); - NEARBY_LOG(INFO, "CreateOutgoingPayload: payload_id=%" PRIX64, payload_id); - MutexLock lock(&mutex_); - pending_payloads_.StartTrackingPayload( - payload_id, absl::make_unique(std::move(internal_payload), - endpoint_ids, - /*is_incoming=*/false)); - - return payload_id; -} - -PayloadManager::PayloadManager(EndpointManager& endpoint_manager) - : endpoint_manager_(&endpoint_manager) { - handle_ = endpoint_manager_->RegisterFrameProcessor(V1Frame::PAYLOAD_TRANSFER, - this); -} - -void PayloadManager::CancelAllPayloads() { - NEARBY_LOG(INFO, "PayloadManager: canceling payloads; self=%p", this); - { - MutexLock lock(&mutex_); - int pending_outgoing_payloads = 0; - for (const auto& pending_id : pending_payloads_.GetAllPayloads()) { - auto* pending = pending_payloads_.GetPayload(pending_id); - if (!pending->IsIncoming()) pending_outgoing_payloads++; - pending->MarkLocallyCanceled(); - pending->Close(); // To unblock the sender thread, if there is no data. - } - if (pending_outgoing_payloads) { - shutdown_barrier_ = - absl::make_unique(pending_outgoing_payloads); - } - } - - if (shutdown_barrier_) { - NEARBY_LOG(INFO, - "PayloadManager: waiting for pending outgoing payloads; self=%p", - this); - shutdown_barrier_->Await(); - } -} - -void PayloadManager::DisconnectFromEndpointManager() { - if (shutdown_.Set(true)) return; - // Unregister ourselves from the FrameProcessors. - endpoint_manager_->UnregisterFrameProcessor(V1Frame::PAYLOAD_TRANSFER, - handle_, true); -} - -PayloadManager::~PayloadManager() { - NEARBY_LOG(INFO, "PayloadManager: going down; self=%p", this); - DisconnectFromEndpointManager(); - CancelAllPayloads(); - NEARBY_LOG(INFO, "PayloadManager: turn down payload executors; self=%p", - this); - bytes_payload_executor_.Shutdown(); - stream_payload_executor_.Shutdown(); - file_payload_executor_.Shutdown(); - - CountDownLatch stop_latch(1); - // Clear our tracked pending payloads. - RunOnStatusUpdateThread([this, &stop_latch]() { - NEARBY_LOG(INFO, "PayloadManager: stop tracking payloads; self=%p", this); - MutexLock lock(&mutex_); - for (const auto& pending_id : pending_payloads_.GetAllPayloads()) { - pending_payloads_.StopTrackingPayload(pending_id); - } - stop_latch.CountDown(); - }); - stop_latch.Await(); - - NEARBY_LOG(INFO, "PayloadManager: turn down notification executor; self=%p", - this); - // Stop all the ongoing Runnables (as gracefully as possible). - payload_status_update_executor_.Shutdown(); - - NEARBY_LOG(INFO, "PayloadManager: down; self=%p", this); -} - -bool PayloadManager::NotifyShutdown() { - MutexLock lock(&mutex_); - if (!shutdown_.Get()) return false; - if (!shutdown_barrier_) return false; - NEARBY_LOG(INFO, "PayloadManager [shutdown mode]"); - shutdown_barrier_->CountDown(); - return true; -} - -void PayloadManager::SendPayload(ClientProxy* client, - const EndpointIds& endpoint_ids, - Payload payload) { - if (shutdown_.Get()) return; - NEARBY_LOG(INFO, "SendPayload: endpoint_ids={%s}", - ToString(endpoint_ids).c_str()); - auto executor = GetOutgoingPayloadExecutor(payload.GetType()); - // The |executor| will be null if the payload is of a type we cannot work - // with. This should never be reached since the ServiceControllerRouter has - // already checked whether or not we can work with this Payload type. - if (!executor) { - NEARBY_LOG(INFO, - "PayloadManager::SendPayload: unsupported: id=%" PRIX64 - ", type=%d", - payload.GetId(), payload.GetType()); - return; - } - - // Each payload is sent in FCFS order within each Payload type, blocking any - // other payload of the same type from even starting until this one is - // completely done with. If we ever want to provide isolation across - // ClientProxy objects this will need to be significantly re-architected. - Payload::Type payload_type = payload.GetType(); - Payload::Id payload_id = - CreateOutgoingPayload(std::move(payload), endpoint_ids); - executor->Execute([this, client, endpoint_ids, payload_id]() { - if (shutdown_.Get()) return; - PendingPayload* pending_payload = GetPayload(payload_id); - if (!pending_payload) return; - auto* internal_payload = pending_payload->GetInternalPayload(); - if (!internal_payload) return; - PayloadTransferFrame::PayloadHeader payload_header{ - CreatePayloadHeader(*internal_payload)}; - bool should_continue = true; - std::int64_t next_chunk_offset = 0; - while (should_continue && !shutdown_.Get()) { - should_continue = SendPayloadLoop(client, *pending_payload, - payload_header, next_chunk_offset); - } - RunOnStatusUpdateThread( - [this, payload_id]() { DestroyPendingPayload(payload_id); }); - }); - NEARBY_LOG(INFO, - "PayloadManager: xfer scheduled: self=%p; id=%" PRIX64 ", type=%d", - this, payload_id, payload_type); -} - -PayloadManager::PendingPayload* PayloadManager::GetPayload( - Payload::Id payload_id) const { - MutexLock lock(&mutex_); - return pending_payloads_.GetPayload(payload_id); -} - -Status PayloadManager::CancelPayload(ClientProxy* client, - Payload::Id payload_id) { - PendingPayload* canceled_payload = GetPayload(payload_id); - if (!canceled_payload) { - NEARBY_LOG(INFO, "PayloadManager: not found; payload_id=%" PRIX64, - payload_id); - return {Status::kPayloadUnknown}; - } - - // Mark the payload as canceled. - canceled_payload->MarkLocallyCanceled(); - NEARBY_LOG(INFO, "PayloadManager: canceled; id=%" PRIX64, payload_id); - - // Return SUCCESS immediately. Remaining cleanup and updates will be sent in - // SendPayload() or OnIncomingFrame() - return {Status::kSuccess}; -} - -// @EndpointManagerDataPool -void PayloadManager::OnIncomingFrame( - OfflineFrame& offline_frame, const std::string& from_endpoint_id, - ClientProxy* to_client, proto::connections::Medium current_medium) { - PayloadTransferFrame& frame = - *offline_frame.mutable_v1()->mutable_payload_transfer(); - - switch (frame.packet_type()) { - case PayloadTransferFrame::CONTROL: - NEARBY_LOG(INFO, - "PayloadManager::OnIncomingFrame [CONTROL]: self=%p; id=%s", - this, from_endpoint_id.c_str()); - ProcessControlPacket(to_client, from_endpoint_id, frame); - break; - case PayloadTransferFrame::DATA: - NEARBY_LOG(INFO, "PayloadManager::OnIncomingFrame [DATA]: self=%p; id=%s", - this, from_endpoint_id.c_str()); - ProcessDataPacket(to_client, from_endpoint_id, frame); - break; - default: - NEARBY_LOG( - INFO, - "PayloadManager: invalid frame; remote endpoint: self=%p; id=%s", - this, from_endpoint_id.c_str()); - break; - } - NEARBY_LOG(INFO, "PayloadManager::OnIncomingFrame [DONE]: self=%p; id=%s", - this, from_endpoint_id.c_str()); -} - -void PayloadManager::OnEndpointDisconnect(ClientProxy* client, - const std::string& endpoint_id, - CountDownLatch* barrier) { - if (shutdown_.Get()) { - if (barrier) barrier->CountDown(); - return; - } - RunOnStatusUpdateThread([this, client, endpoint_id, barrier]() { - // Iterate through all our payloads and look for payloads associated - // with this endpoint. - MutexLock lock(&mutex_); - for (const auto& payload_id : pending_payloads_.GetAllPayloads()) { - auto* pending_payload = pending_payloads_.GetPayload(payload_id); - if (!pending_payload) continue; - auto endpoint_info = pending_payload->GetEndpoint(endpoint_id); - if (!endpoint_info) continue; - - // Stop tracking the endpoint for this payload. - pending_payload->RemoveEndpoints({endpoint_id}); - - std::int64_t payload_total_size = - pending_payload->GetInternalPayload()->GetTotalSize(); - - // If no endpoints are left for this payload, close it. - if (pending_payload->GetEndpoints().empty()) { - pending_payload->Close(); - } - - // Create the payload transfer update. - PayloadProgressInfo update{payload_id, - PayloadProgressInfo::Status::kFailure, - payload_total_size, endpoint_info->offset}; - - // Send a client notification of a payload transfer failure. - client->OnPayloadProgress(endpoint_id, update); - } - - barrier->CountDown(); - }); -} - -proto::connections::PayloadStatus -PayloadManager::EndpointInfoStatusToPayloadStatus(EndpointInfo::Status status) { - switch (status) { - case EndpointInfo::Status::kCanceled: - return proto::connections::PayloadStatus::REMOTE_CANCELLATION; - case EndpointInfo::Status::kError: - return proto::connections::PayloadStatus::REMOTE_ERROR; - case EndpointInfo::Status::kAvailable: - return proto::connections::PayloadStatus::SUCCESS; - default: - NEARBY_LOG(INFO, "PayloadManager: unknown status=%d", status); - return proto::connections::PayloadStatus::UNKNOWN_PAYLOAD_STATUS; - } -} - -proto::connections::PayloadStatus -PayloadManager::ControlMessageEventToPayloadStatus( - PayloadTransferFrame::ControlMessage::EventType event) { - switch (event) { - case PayloadTransferFrame::ControlMessage::PAYLOAD_ERROR: - return proto::connections::PayloadStatus::REMOTE_ERROR; - case PayloadTransferFrame::ControlMessage::PAYLOAD_CANCELED: - return proto::connections::PayloadStatus::REMOTE_CANCELLATION; - default: - NEARBY_LOG(INFO, "PayloadManager: unknown event=%d", event); - return proto::connections::PayloadStatus::UNKNOWN_PAYLOAD_STATUS; - } -} - -PayloadProgressInfo::Status PayloadManager::PayloadStatusToTransferUpdateStatus( - proto::connections::PayloadStatus status) { - switch (status) { - case proto::connections::LOCAL_CANCELLATION: - case proto::connections::REMOTE_CANCELLATION: - return PayloadProgressInfo::Status::kCanceled; - case proto::connections::SUCCESS: - return PayloadProgressInfo::Status::kSuccess; - default: - return PayloadProgressInfo::Status::kFailure; - } -} - -SingleThreadExecutor* PayloadManager::GetOutgoingPayloadExecutor( - Payload::Type payload_type) { - switch (payload_type) { - case Payload::Type::kBytes: - return &bytes_payload_executor_; - case Payload::Type::kFile: - return &file_payload_executor_; - case Payload::Type::kStream: - return &stream_payload_executor_; - default: - return nullptr; - } -} - -PayloadTransferFrame::PayloadHeader PayloadManager::CreatePayloadHeader( - const InternalPayload& internal_payload) { - PayloadTransferFrame::PayloadHeader payload_header; - - payload_header.set_id(internal_payload.GetId()); - payload_header.set_type(internal_payload.GetType()); - payload_header.set_total_size(internal_payload.GetTotalSize()); - - return payload_header; -} - -PayloadTransferFrame::PayloadChunk PayloadManager::CreatePayloadChunk( - std::int64_t payload_chunk_offset, ByteArray payload_chunk_body) { - PayloadTransferFrame::PayloadChunk payload_chunk; - - payload_chunk.set_offset(payload_chunk_offset); - payload_chunk.set_flags(0); - if (!payload_chunk_body.Empty()) { - payload_chunk.set_body(std::string(std::move(payload_chunk_body))); - } else { - payload_chunk.set_flags(payload_chunk.flags() | - PayloadTransferFrame::PayloadChunk::LAST_CHUNK); - } - - return payload_chunk; -} - -PayloadManager::PendingPayload* PayloadManager::CreateIncomingPayload( - const PayloadTransferFrame& frame, const std::string& endpoint_id) { - auto internal_payload = CreateIncomingInternalPayload(frame); - if (!internal_payload) { - return nullptr; - } - - Payload::Id payload_id = internal_payload->GetId(); - NEARBY_LOG(INFO, "CreateIncomingPayload: payload_id=%" PRIX64, payload_id); - MutexLock lock(&mutex_); - pending_payloads_.StartTrackingPayload( - payload_id, - absl::make_unique(std::move(internal_payload), - EndpointIds{endpoint_id}, true)); - - return pending_payloads_.GetPayload(payload_id); -} - -void PayloadManager::SendClientCallbacksForFinishedOutgoingPayload( - ClientProxy* client, const EndpointIds& finished_endpoint_ids, - const PayloadTransferFrame::PayloadHeader& payload_header, - std::int64_t num_bytes_successfully_transferred, - proto::connections::PayloadStatus status) { - RunOnStatusUpdateThread([this, client, finished_endpoint_ids, payload_header, - num_bytes_successfully_transferred, status]() { - // Make sure we're still tracking this payload. - PendingPayload* pending_payload = GetPayload(payload_header.id()); - if (!pending_payload) { - return; - } - - PayloadProgressInfo update{ - payload_header.id(), - PayloadManager::PayloadStatusToTransferUpdateStatus(status), - payload_header.total_size(), num_bytes_successfully_transferred}; - for (const auto& endpoint_id : finished_endpoint_ids) { - // Skip sending notifications if we have stopped tracking this - // endpoint. - if (!pending_payload->GetEndpoint(endpoint_id)) { - continue; - } - - // Notify the client. - client->OnPayloadProgress(endpoint_id, update); - } - - // Remove these endpoints from our tracking list for this payload. - pending_payload->RemoveEndpoints(finished_endpoint_ids); - - // Close the payload if no endpoints remain. - if (pending_payload->GetEndpoints().empty()) { - pending_payload->Close(); - } - }); -} - -void PayloadManager::SendClientCallbacksForFinishedIncomingPayload( - ClientProxy* client, const std::string& endpoint_id, - const PayloadTransferFrame::PayloadHeader& payload_header, - std::int64_t offset_bytes, proto::connections::PayloadStatus status) { - RunOnStatusUpdateThread( - [this, client, endpoint_id, payload_header, offset_bytes, status]() { - // Make sure we're still tracking this payload. - PendingPayload* pending_payload = GetPayload(payload_header.id()); - if (!pending_payload) { - return; - } - - // Unless we never started tracking this payload (meaning we failed to - // even create the InternalPayload), notify the client (and close it). - PayloadProgressInfo update{ - payload_header.id(), - PayloadManager::PayloadStatusToTransferUpdateStatus(status), - payload_header.total_size(), offset_bytes}; - NotifyClientOfIncomingPayloadProgressInfo(client, endpoint_id, update); - DestroyPendingPayload(payload_header.id()); - }); -} - -void PayloadManager::SendControlMessage( - const EndpointIds& endpoint_ids, - const PayloadTransferFrame::PayloadHeader& payload_header, - std::int64_t num_bytes_successfully_transferred, - PayloadTransferFrame::ControlMessage::EventType event_type) { - PayloadTransferFrame::ControlMessage control_message; - control_message.set_event(event_type); - control_message.set_offset(num_bytes_successfully_transferred); - - endpoint_manager_->SendControlMessage(payload_header, control_message, - endpoint_ids); -} - -void PayloadManager::HandleFinishedOutgoingPayload( - ClientProxy* client, const EndpointIds& finished_endpoint_ids, - const PayloadTransferFrame::PayloadHeader& payload_header, - std::int64_t num_bytes_successfully_transferred, - proto::connections::PayloadStatus status) { - // This call will destroy a pending payload. - SendClientCallbacksForFinishedOutgoingPayload( - client, finished_endpoint_ids, payload_header, - num_bytes_successfully_transferred, status); - - switch (status) { - case proto::connections::PayloadStatus::LOCAL_ERROR: - SendControlMessage(finished_endpoint_ids, payload_header, - num_bytes_successfully_transferred, - PayloadTransferFrame::ControlMessage::PAYLOAD_ERROR); - break; - case proto::connections::PayloadStatus::LOCAL_CANCELLATION: - NEARBY_LOG(INFO, - "Sending PAYLOAD_CANCEL to receiver side; payload_id=%" PRIX64, - static_cast(payload_header.id())); - SendControlMessage( - finished_endpoint_ids, payload_header, - num_bytes_successfully_transferred, - PayloadTransferFrame::ControlMessage::PAYLOAD_CANCELED); - break; - case proto::connections::PayloadStatus::ENDPOINT_IO_ERROR: - // Unregister these endpoints, since we had an IO error on the physical - // connection. - for (const auto& endpoint_id : finished_endpoint_ids) { - endpoint_manager_->DiscardEndpoint(client, endpoint_id); - } - break; - case proto::connections::PayloadStatus::REMOTE_ERROR: - case proto::connections::PayloadStatus::REMOTE_CANCELLATION: - // No special handling needed for these. - break; - default: - NEARBY_LOG(INFO, "PayloadManager: unknown status=%d", status); - break; - } -} - -void PayloadManager::HandleFinishedIncomingPayload( - ClientProxy* client, const std::string& endpoint_id, - const PayloadTransferFrame::PayloadHeader& payload_header, - std::int64_t offset_bytes, proto::connections::PayloadStatus status) { - SendClientCallbacksForFinishedIncomingPayload( - client, endpoint_id, payload_header, offset_bytes, status); - - switch (status) { - case proto::connections::PayloadStatus::LOCAL_ERROR: - SendControlMessage({endpoint_id}, payload_header, offset_bytes, - PayloadTransferFrame::ControlMessage::PAYLOAD_ERROR); - break; - case proto::connections::PayloadStatus::LOCAL_CANCELLATION: - SendControlMessage( - {endpoint_id}, payload_header, offset_bytes, - PayloadTransferFrame::ControlMessage::PAYLOAD_CANCELED); - break; - default: - // TODO(tracyzhou): Add logging. - break; - } -} - -void PayloadManager::HandleSuccessfulOutgoingChunk( - ClientProxy* client, const std::string& endpoint_id, - const PayloadTransferFrame::PayloadHeader& payload_header, - std::int32_t payload_chunk_flags, std::int64_t payload_chunk_offset, - std::int64_t payload_chunk_body_size) { - RunOnStatusUpdateThread([this, client, endpoint_id, payload_header, - payload_chunk_flags, payload_chunk_offset, - payload_chunk_body_size]() { - // Make sure we're still tracking this payload and its associated - // endpoint. - PendingPayload* pending_payload = GetPayload(payload_header.id()); - if (!pending_payload || !pending_payload->GetEndpoint(endpoint_id)) { - NEARBY_LOG(INFO, - "HandleSuccessfulOutgoingChunk: endpoint not found: id=%s", - endpoint_id.c_str()); - return; - } - - bool is_last_chunk = (payload_chunk_flags & - PayloadTransferFrame::PayloadChunk::LAST_CHUNK) != 0; - PayloadProgressInfo update{ - payload_header.id(), - is_last_chunk ? PayloadProgressInfo::Status::kSuccess - : PayloadProgressInfo::Status::kInProgress, - payload_header.total_size(), - is_last_chunk ? payload_chunk_offset - : payload_chunk_offset + payload_chunk_body_size}; - - // Notify the client. - client->OnPayloadProgress(endpoint_id, update); - - if (is_last_chunk) { - // Stop tracking this endpoint. - pending_payload->RemoveEndpoints({endpoint_id}); - - // Close the payload if no endpoints remain. - if (pending_payload->GetEndpoints().empty()) { - pending_payload->Close(); - } - } - }); -} - -// @PayloadManagerStatusUpdateThread -void PayloadManager::DestroyPendingPayload(Payload::Id payload_id) { - bool is_incoming = false; - { - MutexLock lock(&mutex_); - auto pending = pending_payloads_.StopTrackingPayload(payload_id); - if (!pending) return; - is_incoming = pending->IsIncoming(); - const char* direction = is_incoming ? "incoming" : "outgoing"; - NEARBY_LOG(INFO, - "PayloadManager: destroying %s pending payload: " - "self=%p; id=%" PRIX64, - direction, this, payload_id); - pending->Close(); - pending.reset(); - } - if (!is_incoming) NotifyShutdown(); -} - -void PayloadManager::HandleSuccessfulIncomingChunk( - ClientProxy* client, const std::string& endpoint_id, - const PayloadTransferFrame::PayloadHeader& payload_header, - std::int32_t payload_chunk_flags, std::int64_t payload_chunk_offset, - std::int64_t payload_chunk_body_size) { - RunOnStatusUpdateThread([this, client, endpoint_id, payload_header, - payload_chunk_flags, payload_chunk_offset, - payload_chunk_body_size]() { - // Make sure we're still tracking this payload. - PendingPayload* pending_payload = GetPayload(payload_header.id()); - if (!pending_payload) { - return; - } - - bool is_last_chunk = (payload_chunk_flags & - PayloadTransferFrame::PayloadChunk::LAST_CHUNK) != 0; - PayloadProgressInfo update{ - payload_header.id(), - is_last_chunk ? PayloadProgressInfo::Status::kSuccess - : PayloadProgressInfo::Status::kInProgress, - payload_header.total_size(), - is_last_chunk ? payload_chunk_offset - : payload_chunk_offset + payload_chunk_body_size}; - - // Notify the client of this update. - NotifyClientOfIncomingPayloadProgressInfo(client, endpoint_id, update); - }); -} - -// @EndpointManagerDataPool -void PayloadManager::ProcessDataPacket( - ClientProxy* to_client, const std::string& from_endpoint_id, - PayloadTransferFrame& payload_transfer_frame) { - PayloadTransferFrame::PayloadHeader& payload_header = - *payload_transfer_frame.mutable_payload_header(); - PayloadTransferFrame::PayloadChunk& payload_chunk = - *payload_transfer_frame.mutable_payload_chunk(); - - PendingPayload* pending_payload; - if (payload_chunk.offset() == 0) { - pending_payload = - CreateIncomingPayload(payload_transfer_frame, from_endpoint_id); - if (!pending_payload) { - // Send the error to the remote endpoint. - SendControlMessage({from_endpoint_id}, payload_header, - payload_chunk.offset(), - PayloadTransferFrame::ControlMessage::PAYLOAD_ERROR); - return; - } - - // Also, let the client know of this new incoming payload. - RunOnStatusUpdateThread([to_client, from_endpoint_id, pending_payload]() { - NEARBY_LOG(INFO, "ProcessDataPacket [new]: id=%s; payload_id=%" PRIX64, - from_endpoint_id.c_str(), pending_payload->GetId()); - to_client->OnPayload( - from_endpoint_id, - pending_payload->GetInternalPayload()->ReleasePayload()); - }); - } else { - pending_payload = GetPayload(payload_header.id()); - if (!pending_payload) { - NEARBY_LOG(INFO, - "ProcessDataPacket: [missing] id=%s; payload_id=%" PRIX64, - from_endpoint_id.c_str(), - static_cast(payload_header.id())); - return; - } - } - - if (pending_payload->IsLocallyCanceled()) { - // This incoming payload was canceled by the client. Drop this frame and do - // all the cleanup. See go/nc-cancel-payload - NEARBY_LOG(INFO, "ProcessDataPacket: [cancel] id=%s; payload_id=%" PRIX64, - from_endpoint_id.c_str(), pending_payload->GetId()); - HandleFinishedIncomingPayload( - to_client, from_endpoint_id, payload_header, payload_chunk.offset(), - proto::connections::PayloadStatus::LOCAL_CANCELLATION); - return; - } - - // Update the offset for this payload. An endpoint disconnection might occur - // from another thread and we would need to know the current offset to report - // back to the client. For the sake of accuracy, we update the pending payload - // here because it's after all payload terminating events are handled, but - // right before we actually start attaching the next chunk. - pending_payload->SetOffsetForEndpoint(from_endpoint_id, - payload_chunk.offset()); - - // Save size of packet before we move it. - std::int64_t payload_body_size = payload_chunk.body().size(); - if (pending_payload->GetInternalPayload() - ->AttachNextChunk(ByteArray(std::move(*payload_chunk.mutable_body()))) - .Raised()) { - NEARBY_LOG(INFO, - "ProcessDataPacket: [data: error] id=%s; payload_id=%" PRIX64, - from_endpoint_id.c_str(), pending_payload->GetId()); - HandleFinishedIncomingPayload( - to_client, from_endpoint_id, payload_header, payload_chunk.offset(), - proto::connections::PayloadStatus::LOCAL_ERROR); - return; - } - - NEARBY_LOG(INFO, "ProcessDataPacket: [data: ok] id=%s; payload_id=%" PRIX64, - from_endpoint_id.c_str(), pending_payload->GetId()); - HandleSuccessfulIncomingChunk(to_client, from_endpoint_id, payload_header, - payload_chunk.flags(), payload_chunk.offset(), - payload_body_size); -} - -// @EndpointManagerDataPool -void PayloadManager::ProcessControlPacket( - ClientProxy* to_client, const std::string& from_endpoint_id, - PayloadTransferFrame& payload_transfer_frame) { - const PayloadTransferFrame::PayloadHeader& payload_header = - payload_transfer_frame.payload_header(); - const PayloadTransferFrame::ControlMessage& control_message = - payload_transfer_frame.control_message(); - PendingPayload* pending_payload = GetPayload(payload_header.id()); - if (!pending_payload) { - // TODO(tracyzhou): Add logging. - return; - } - - switch (control_message.event()) { - case PayloadTransferFrame::ControlMessage::PAYLOAD_CANCELED: - if (pending_payload->IsIncoming()) { - NEARBY_LOG(INFO, "Incoming PAYLOAD_CANCELED: from id=%s; self=%p", - from_endpoint_id.c_str(), this); - // No need to mark the pending payload as cancelled, since this is a - // remote cancellation for an incoming payload -- we handle everything - // inline here. - HandleFinishedIncomingPayload( - to_client, from_endpoint_id, payload_header, - control_message.offset(), - ControlMessageEventToPayloadStatus(control_message.event())); - } else { - NEARBY_LOG(INFO, "Outgoing PAYLOAD_CANCELED: from id=%s; self=%p", - from_endpoint_id.c_str(), this); - // Mark the payload as canceled *for this endpoint*. - pending_payload->SetEndpointStatusFromControlMessage(from_endpoint_id, - control_message); - } - // TODO(tracyzhou): Add logging. - break; - case PayloadTransferFrame::ControlMessage::PAYLOAD_ERROR: - if (pending_payload->IsIncoming()) { - HandleFinishedIncomingPayload( - to_client, from_endpoint_id, payload_header, - control_message.offset(), - ControlMessageEventToPayloadStatus(control_message.event())); - } else { - pending_payload->SetEndpointStatusFromControlMessage(from_endpoint_id, - control_message); - } - break; - default: - // TODO(tracyzhou): Add logging. - break; - } -} - -// @PayloadManagerStatusUpdateThread -void PayloadManager::NotifyClientOfIncomingPayloadProgressInfo( - ClientProxy* client, const std::string& endpoint_id, - const PayloadProgressInfo& payload_transfer_update) { - client->OnPayloadProgress(endpoint_id, payload_transfer_update); -} - -///////////////////////////////// EndpointInfo ///////////////////////////////// - -PayloadManager::EndpointInfo::Status -PayloadManager::EndpointInfo::ControlMessageEventToEndpointInfoStatus( - PayloadTransferFrame::ControlMessage::EventType event) { - switch (event) { - case PayloadTransferFrame::ControlMessage::PAYLOAD_ERROR: - return Status::kError; - case PayloadTransferFrame::ControlMessage::PAYLOAD_CANCELED: - return Status::kCanceled; - default: - // TODO(tracyzhou): Add logging. - return Status::kUnknown; - } -} - -void PayloadManager::EndpointInfo::SetStatusFromControlMessage( - const PayloadTransferFrame::ControlMessage& control_message) { - status.Set(ControlMessageEventToEndpointInfoStatus(control_message.event())); -} - -//////////////////////////////// PendingPayload //////////////////////////////// - -PayloadManager::PendingPayload::PendingPayload( - std::unique_ptr internal_payload, - const EndpointIds& endpoint_ids, bool is_incoming) - : is_incoming_(is_incoming), - internal_payload_(std::move(internal_payload)) { - // Initially we mark all endpoints as available. - // Later on some may become canceled, some may experience data transfer - // failures. Any of these situations will cause endpoint to be marked as - // unavailable. - for (const auto& id : endpoint_ids) { - endpoints_.emplace(id, EndpointInfo{ - .id = id, - .status {EndpointInfo::Status::kAvailable}, - }); - } -} - -Payload::Id PayloadManager::PendingPayload::GetId() const { - return internal_payload_->GetId(); -} - -InternalPayload* PayloadManager::PendingPayload::GetInternalPayload() { - return internal_payload_.get(); -} - -bool PayloadManager::PendingPayload::IsLocallyCanceled() const { - return is_locally_canceled_.Get(); -} - -void PayloadManager::PendingPayload::MarkLocallyCanceled() { - is_locally_canceled_.Set(true); -} - -bool PayloadManager::PendingPayload::IsIncoming() const { return is_incoming_; } - -std::vector -PayloadManager::PendingPayload::GetEndpoints() const { - MutexLock lock(&mutex_); - - std::vector result; - for (const auto& item : endpoints_) { - result.push_back(&item.second); - } - return result; -} - -PayloadManager::EndpointInfo* PayloadManager::PendingPayload::GetEndpoint( - const std::string& endpoint_id) { - MutexLock lock(&mutex_); - - auto it = endpoints_.find(endpoint_id); - if (it == endpoints_.end()) { - return {}; - } - - return &it->second; -} - -void PayloadManager::PendingPayload::RemoveEndpoints( - const EndpointIds& endpoint_ids) { - MutexLock lock(&mutex_); - - for (const auto& id : endpoint_ids) { - endpoints_.erase(id); - } -} - -void PayloadManager::PendingPayload::SetEndpointStatusFromControlMessage( - const std::string& endpoint_id, - const PayloadTransferFrame::ControlMessage& control_message) { - MutexLock lock(&mutex_); - - auto item = endpoints_.find(endpoint_id); - if (item != endpoints_.end()) { - item->second.SetStatusFromControlMessage(control_message); - } -} - -void PayloadManager::PendingPayload::SetOffsetForEndpoint( - const std::string& endpoint_id, std::int64_t offset) { - MutexLock lock(&mutex_); - - auto item = endpoints_.find(endpoint_id); - if (item != endpoints_.end()) { - item->second.offset = offset; - } -} - -void PayloadManager::PendingPayload::Close() { - if (internal_payload_) internal_payload_->Close(); - close_event_.CountDown(); -} - -bool PayloadManager::PendingPayload::WaitForClose() { - return close_event_.Await(kWaitCloseTimeout).result(); -} - -bool PayloadManager::PendingPayload::IsClosed() { - return close_event_.Await(absl::ZeroDuration()).result(); -} - -void PayloadManager::RunOnStatusUpdateThread(std::function runnable) { - payload_status_update_executor_.Execute(std::move(runnable)); -} - -/////////////////////////////// PendingPayloads /////////////////////////////// - -void PayloadManager::PendingPayloads::StartTrackingPayload( - Payload::Id payload_id, std::unique_ptr pending_payload) { - MutexLock lock(&mutex_); - - auto pair = pending_payloads_.emplace(payload_id, std::move(pending_payload)); - NEARBY_LOG(INFO, "StartTrackingPayload: payload_id=%" PRIX64 "; inserted=%d", - payload_id, pair.second); -} - -std::unique_ptr -PayloadManager::PendingPayloads::StopTrackingPayload(Payload::Id payload_id) { - MutexLock lock(&mutex_); - - auto it = pending_payloads_.find(payload_id); - if (it == pending_payloads_.end()) return {}; - - auto item = pending_payloads_.extract(it); - return std::move(item.mapped()); -} - -PayloadManager::PendingPayload* PayloadManager::PendingPayloads::GetPayload( - Payload::Id payload_id) const { - MutexLock lock(&mutex_); - - auto item = pending_payloads_.find(payload_id); - return item != pending_payloads_.end() ? item->second.get() : nullptr; -} - -std::vector PayloadManager::PendingPayloads::GetAllPayloads() { - MutexLock lock(&mutex_); - - std::vector result; - for (const auto& item : pending_payloads_) { - result.push_back(item.first); - } - return result; -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/payload_manager.h b/cpp/core_v2/internal/payload_manager.h deleted file mode 100644 index 3df1fe5a..00000000 --- a/cpp/core_v2/internal/payload_manager.h +++ /dev/null @@ -1,285 +0,0 @@ -#ifndef CORE_V2_INTERNAL_PAYLOAD_MANAGER_H_ -#define CORE_V2_INTERNAL_PAYLOAD_MANAGER_H_ - -#include -#include -#include -#include - -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/endpoint_manager.h" -#include "core_v2/internal/internal_payload.h" -#include "core_v2/listeners.h" -#include "core_v2/payload.h" -#include "core_v2/status.h" -#include "proto/connections/offline_wire_formats.pb.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/public/atomic_boolean.h" -#include "platform_v2/public/atomic_reference.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/mutex.h" -#include "proto/connections_enums.pb.h" -#include "absl/container/flat_hash_map.h" - -namespace location { -namespace nearby { -namespace connections { - -class PayloadManager : public EndpointManager::FrameProcessor { - public: - using EndpointIds = std::vector; - constexpr static const absl::Duration kWaitCloseTimeout = - absl::Milliseconds(5000); - - explicit PayloadManager(EndpointManager& endpoint_manager); - ~PayloadManager() override; - - void SendPayload(ClientProxy* client, const EndpointIds& endpoint_ids, - Payload payload); - Status CancelPayload(ClientProxy* client, Payload::Id payload_id); - - // @EndpointManagerReaderThread - void OnIncomingFrame(OfflineFrame& offline_frame, - const std::string& from_endpoint_id, - ClientProxy* to_client, - proto::connections::Medium current_medium) override; - - // @EndpointManagerThread - void OnEndpointDisconnect(ClientProxy* client, const std::string& endpoint_id, - CountDownLatch* barrier) override; - - void DisconnectFromEndpointManager(); - - private: - // Information about an endpoint for a particular payload. - struct EndpointInfo { - // Status set for the endpoint out-of-band via a ControlMessage. - enum class Status { - kUnknown, - kAvailable, - kCanceled, - kError, - }; - - void SetStatusFromControlMessage( - const PayloadTransferFrame::ControlMessage& control_message); - - static Status ControlMessageEventToEndpointInfoStatus( - PayloadTransferFrame::ControlMessage::EventType event); - - std::string id; - AtomicReference status {Status::kUnknown}; - std::int64_t offset = 0; - }; - - // Tracks state for an InternalPayload and the endpoints associated with it. - class PendingPayload { - public: - PendingPayload(std::unique_ptr internal_payload, - const EndpointIds& endpoint_ids, bool is_incoming); - PendingPayload(PendingPayload&&) = default; - PendingPayload& operator=(PendingPayload&&) = default; - - ~PendingPayload() { Close(); } - - Payload::Id GetId() const; - - InternalPayload* GetInternalPayload(); - - bool IsLocallyCanceled() const; - void MarkLocallyCanceled(); - bool IsIncoming() const; - - // Gets the EndpointInfo objects for the endpoints (still) associated with - // this payload. - std::vector GetEndpoints() const - ABSL_LOCKS_EXCLUDED(mutex_); - // Returns the EndpointInfo for a given endpoint ID. Returns null if the - // endpoint is not associated with this payload. - EndpointInfo* GetEndpoint(const std::string& endpoint_id) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Removes the given endpoints, e.g. on error. - void RemoveEndpoints(const EndpointIds& endpoint_ids_to_remove) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Sets the status for a particular endpoint. - void SetEndpointStatusFromControlMessage( - const std::string& endpoint_id, - const PayloadTransferFrame::ControlMessage& control_message) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Sets the offset for a particular endpoint. - void SetOffsetForEndpoint(const std::string& endpoint_id, - std::int64_t offset) ABSL_LOCKS_EXCLUDED(mutex_); - - // Closes internal_payload_ and triggers close_event_. - // Close is called when a pending peyload does not have associated - // endpoints. - void Close(); - - // Waits for close_event_ or for timeout to happen. - // Returns true, if event happened, false otherwise. - bool WaitForClose(); - bool IsClosed(); - - private: - mutable Mutex mutex_; - bool is_incoming_; - AtomicBoolean is_locally_canceled_{false}; - CountDownLatch close_event_{1}; - std::unique_ptr internal_payload_; - absl::flat_hash_map endpoints_ - ABSL_GUARDED_BY(mutex_); - }; - - // Tracks and manages PendingPayload objects in a synchronized manner. - class PendingPayloads { - public: - PendingPayloads() = default; - ~PendingPayloads() = default; - - void StartTrackingPayload(Payload::Id payload_id, - std::unique_ptr pending_payload) - ABSL_LOCKS_EXCLUDED(mutex_); - std::unique_ptr StopTrackingPayload(Payload::Id payload_id) - ABSL_LOCKS_EXCLUDED(mutex_); - PendingPayload* GetPayload(Payload::Id payload_id) const - ABSL_LOCKS_EXCLUDED(mutex_); - std::vector GetAllPayloads() ABSL_LOCKS_EXCLUDED(mutex_); - - private: - mutable Mutex mutex_; - absl::flat_hash_map> - pending_payloads_ ABSL_GUARDED_BY(mutex_); - }; - - using Endpoints = std::vector; - static std::string ToString(const EndpointIds& endpoint_ids); - static std::string ToString(const Endpoints& endpoints); - - // Splits the endpoints for this payload by availability. - // Returns a pair of lists of EndpointInfo*, with the first being the list of - // still-available endpoints, and the second for unavailable endpoints. - static std::pair GetAvailableAndUnavailableEndpoints( - const PendingPayload& pending_payload); - - // Converts list of EndpointInfo to list of Endpoint ids. - // Returns list of endpoint ids. - static EndpointIds EndpointsToEndpointIds(const Endpoints& endpoints); - - bool SendPayloadLoop(ClientProxy* client, PendingPayload& pending_payload, - PayloadTransferFrame::PayloadHeader& payload_header, - std::int64_t& next_chunk_offset); - void SendClientCallbacksForFinishedIncomingPayloadRunnable( - ClientProxy* client, const std::string& endpoint_id, - const PayloadTransferFrame::PayloadHeader& payload_header, - std::int64_t offset_bytes, proto::connections::PayloadStatus status); - - // Converts the status of an endpoint that's been set out-of-band via a remote - // ControlMessage to the PayloadStatus for handling of that endpoint-payload - // pair. - static proto::connections::PayloadStatus EndpointInfoStatusToPayloadStatus( - EndpointInfo::Status status); - // Converts a ControlMessage::EventType for a particular payload to a - // PayloadStatus. Called when we've received a ControlMessage with this event - // from a remote endpoint; thus the PayloadStatuses are REMOTE_*. - static proto::connections::PayloadStatus ControlMessageEventToPayloadStatus( - PayloadTransferFrame::ControlMessage::EventType event); - static PayloadProgressInfo::Status PayloadStatusToTransferUpdateStatus( - proto::connections::PayloadStatus status); - - PayloadTransferFrame::PayloadHeader CreatePayloadHeader( - const InternalPayload& payload); - PayloadTransferFrame::PayloadChunk CreatePayloadChunk(std::int64_t offset, - ByteArray body); - - PendingPayload* CreateIncomingPayload(const PayloadTransferFrame& frame, - const std::string& endpoint_id) - ABSL_LOCKS_EXCLUDED(mutex_); - - Payload::Id CreateOutgoingPayload(Payload payload, - const EndpointIds& endpoint_ids) - ABSL_LOCKS_EXCLUDED(mutex_); - - void SendClientCallbacksForFinishedOutgoingPayload( - ClientProxy* client, const EndpointIds& finished_endpoint_ids, - const PayloadTransferFrame::PayloadHeader& payload_header, - std::int64_t num_bytes_successfully_transferred, - proto::connections::PayloadStatus status); - void SendClientCallbacksForFinishedIncomingPayload( - ClientProxy* client, const std::string& endpoint_id, - const PayloadTransferFrame::PayloadHeader& payload_header, - std::int64_t offset_bytes, proto::connections::PayloadStatus status); - - void SendControlMessage( - const EndpointIds& endpoint_ids, - const PayloadTransferFrame::PayloadHeader& payload_header, - std::int64_t num_bytes_successfully_transferred, - PayloadTransferFrame::ControlMessage::EventType event_type); - - // Handles a finished outgoing payload for the given endpointIds. All statuses - // except for SUCCESS are handled here. - void HandleFinishedOutgoingPayload( - ClientProxy* client, const EndpointIds& finished_endpoint_ids, - const PayloadTransferFrame::PayloadHeader& payload_header, - std::int64_t num_bytes_successfully_transferred, - proto::connections::PayloadStatus status = - proto::connections::PayloadStatus::UNKNOWN_PAYLOAD_STATUS); - void HandleFinishedIncomingPayload( - ClientProxy* client, const std::string& endpoint_id, - const PayloadTransferFrame::PayloadHeader& payload_header, - std::int64_t offset_bytes, proto::connections::PayloadStatus status); - - void HandleSuccessfulOutgoingChunk( - ClientProxy* client, const std::string& endpoint_id, - const PayloadTransferFrame::PayloadHeader& payload_header, - std::int32_t payload_chunk_flags, std::int64_t payload_chunk_offset, - std::int64_t payload_chunk_body_size); - void HandleSuccessfulIncomingChunk( - ClientProxy* client, const std::string& endpoint_id, - const PayloadTransferFrame::PayloadHeader& payload_header, - std::int32_t payload_chunk_flags, std::int64_t payload_chunk_offset, - std::int64_t payload_chunk_body_size); - - void ProcessDataPacket(ClientProxy* to_client, - const std::string& from_endpoint_id, - PayloadTransferFrame& payload_transfer_frame); - void ProcessControlPacket(ClientProxy* to_client, - const std::string& from_endpoint_id, - PayloadTransferFrame& payload_transfer_frame); - - // @PayloadStatusUpdateThread - void NotifyClientOfIncomingPayloadProgressInfo( - ClientProxy* client, const std::string& endpoint_id, - const PayloadProgressInfo& payload_transfer_update); - - SingleThreadExecutor* GetOutgoingPayloadExecutor(Payload::Type payload_type); - - void RunOnStatusUpdateThread(std::function runnable); - bool NotifyShutdown() ABSL_LOCKS_EXCLUDED(mutex_); - void DestroyPendingPayload(Payload::Id payload_id) - ABSL_LOCKS_EXCLUDED(mutex_); - PendingPayload* GetPayload(Payload::Id payload_id) const - ABSL_LOCKS_EXCLUDED(mutex_); - void CancelAllPayloads() ABSL_LOCKS_EXCLUDED(mutex_); - - mutable Mutex mutex_; - EndpointManager::FrameProcessor::Handle handle_; - AtomicBoolean shutdown_{false}; - std::unique_ptr shutdown_barrier_; - int send_payload_count_ = 0; - PendingPayloads pending_payloads_ ABSL_GUARDED_BY(mutex_); - SingleThreadExecutor bytes_payload_executor_; - SingleThreadExecutor file_payload_executor_; - SingleThreadExecutor stream_payload_executor_; - SingleThreadExecutor payload_status_update_executor_; - - EndpointManager* endpoint_manager_; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_PAYLOAD_MANAGER_H_ diff --git a/cpp/core_v2/internal/pcp.h b/cpp/core_v2/internal/pcp.h deleted file mode 100644 index f2fec5ea..00000000 --- a/cpp/core_v2/internal/pcp.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef CORE_V2_INTERNAL_PCP_H_ -#define CORE_V2_INTERNAL_PCP_H_ - -namespace location { -namespace nearby { -namespace connections { - -// The PreConnectionProtocol (PCP) defines the combinations of interactions -// between the techniques (ultrasound audio, Bluetooth device names, BLE -// advertisements) used for offline Advertisement + Discovery, and identifies -// the steps to go through on each device. -// -// See go/nearby-offline-data-interchange-formats for more. -enum class Pcp { - kUnknown = 0, - kP2pStar = 1, - kP2pCluster = 2, - kP2pPointToPoint = 3, - // PCP is only allocated 5 bits in our data interchange formats, so there can - // never be more than 31 PCP values. -}; -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_PCP_H_ diff --git a/cpp/core_v2/internal/pcp_handler.h b/cpp/core_v2/internal/pcp_handler.h deleted file mode 100644 index 8997f8a7..00000000 --- a/cpp/core_v2/internal/pcp_handler.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef CORE_V2_INTERNAL_PCP_HANDLER_H_ -#define CORE_V2_INTERNAL_PCP_HANDLER_H_ - -#include - -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/pcp.h" -#include "core_v2/listeners.h" -#include "core_v2/options.h" -#include "core_v2/params.h" -#include "core_v2/status.h" -#include "core_v2/strategy.h" -#include "proto/connections_enums.pb.h" - -namespace location { -namespace nearby { -namespace connections { - -inline Pcp StrategyToPcp(Strategy strategy) { - if (strategy == Strategy::kP2pCluster) return Pcp::kP2pCluster; - if (strategy == Strategy::kP2pStar) return Pcp::kP2pStar; - if (strategy == Strategy::kP2pPointToPoint) return Pcp::kP2pPointToPoint; - return Pcp::kUnknown; -} - -inline Strategy PcpToStrategy(Pcp pcp) { - if (pcp == Pcp::kP2pCluster) return Strategy::kP2pCluster; - if (pcp == Pcp::kP2pStar) return Strategy::kP2pStar; - if (pcp == Pcp::kP2pPointToPoint) return Strategy::kP2pPointToPoint; - return Strategy::kNone; -} - -// Defines the set of methods that need to be implemented to handle the -// per-PCP-specific operations in the OfflineServiceController. -// -// These methods are all meant to be synchronous, and should return only after -// knowing they've done what they were supposed to do (or unequivocally failed -// to do so). -// -// See details here: -// https://source.corp.google.com/piper///depot/google3/core_v2/core.h -class PcpHandler { - public: - virtual ~PcpHandler() = default; - - // Return strategy supported by this protocol. - virtual Strategy GetStrategy() const = 0; - - // Return concrete variant of protocol. - virtual Pcp GetPcp() const = 0; - - // We have been asked by the client to start advertising. Once we successfully - // start advertising, we'll change the ClientProxy's state. - // ConnectionListener (info.listener) will be notified in case of any event. - // See - // https://source.corp.google.com/piper///depot/google3/core_v2/listeners.h;bpv=1;bpt=1;l=71?gsn=ConnectionListener - virtual Status StartAdvertising(ClientProxy* client, - const std::string& service_id, - const ConnectionOptions& options, - const ConnectionRequestInfo& info) = 0; - - // If Advertising is active, stop it, and change CLientProxy state, - // otherwise do nothing. - virtual void StopAdvertising(ClientProxy* client) = 0; - - // Start discovery of endpoints that may be advertising. - // Update ClientProxy state once discovery started. - // DiscoveryListener will get called in case of any event. - virtual Status StartDiscovery(ClientProxy* client, - const std::string& service_id, - const ConnectionOptions& options, - const DiscoveryListener& listener) = 0; - - // If Discovery is active, stop it, and change CLientProxy state, - // otherwise do nothing. - virtual void StopDiscovery(ClientProxy* client) = 0; - - // If remote endpoint has been successfully discovered, request it to form a - // connection, update state on ClientProxy. - virtual Status RequestConnection(ClientProxy* client, - const std::string& endpoint_id, - const ConnectionRequestInfo& info, - const ConnectionOptions& options) = 0; - - // Either party may call this to accept connection on their part. - // Until both parties call it, connection will not reach a data phase. - // Update state in ClientProxy. - virtual Status AcceptConnection(ClientProxy* client, - const std::string& endpoint_id, - const PayloadListener& payload_listener) = 0; - - // Either party may call this to reject connection on their part before - // connection reaches data phase. If either party does call it, connection - // will terminate. Update state in ClientProxy. - virtual Status RejectConnection(ClientProxy* client, - const std::string& endpoint_id) = 0; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_PCP_HANDLER_H_ diff --git a/cpp/core_v2/internal/pcp_manager.cc b/cpp/core_v2/internal/pcp_manager.cc deleted file mode 100644 index 3a537547..00000000 --- a/cpp/core_v2/internal/pcp_manager.cc +++ /dev/null @@ -1,119 +0,0 @@ -#include "core_v2/internal/pcp_manager.h" - -#include "core_v2/internal/p2p_cluster_pcp_handler.h" -#include "core_v2/internal/p2p_point_to_point_pcp_handler.h" -#include "core_v2/internal/p2p_star_pcp_handler.h" -#include "core_v2/internal/pcp_handler.h" - -namespace location { -namespace nearby { -namespace connections { - -PcpManager::PcpManager(Mediums& mediums, - EndpointChannelManager& channel_manager, - EndpointManager& endpoint_manager, - BwuManager& bwu_manager) { - handlers_[Pcp::kP2pCluster] = std::make_unique( - &mediums, &endpoint_manager, &channel_manager, &bwu_manager); - handlers_[Pcp::kP2pStar] = std::make_unique( - mediums, endpoint_manager, channel_manager, bwu_manager); - handlers_[Pcp::kP2pPointToPoint] = - std::make_unique(mediums, endpoint_manager, - channel_manager, bwu_manager); -} - -void PcpManager::DisconnectFromEndpointManager() { - if (shutdown_.Set(true)) return; - for (auto& item : handlers_) { - if (!item.second) continue; - item.second->DisconnectFromEndpointManager(); - } -} - -PcpManager::~PcpManager() { - DisconnectFromEndpointManager(); -} - -Status PcpManager::StartAdvertising(ClientProxy* client, - const string& service_id, - const ConnectionOptions& options, - const ConnectionRequestInfo& info) { - if (!SetCurrentPcpHandler(options.strategy)) { - return {Status::kError}; - } - - return current_->StartAdvertising(client, service_id, options, info); -} - -void PcpManager::StopAdvertising(ClientProxy* client) { - if (current_) { - current_->StopAdvertising(client); - } -} - -Status PcpManager::StartDiscovery(ClientProxy* client, const string& service_id, - const ConnectionOptions& options, - DiscoveryListener listener) { - if (!SetCurrentPcpHandler(options.strategy)) { - return {Status::kError}; - } - - return current_->StartDiscovery(client, service_id, options, - std::move(listener)); -} - -void PcpManager::StopDiscovery(ClientProxy* client) { - if (current_) { - current_->StopDiscovery(client); - } -} - -Status PcpManager::RequestConnection(ClientProxy* client, - const string& endpoint_id, - const ConnectionRequestInfo& info, - const ConnectionOptions& options) { - if (!current_) { - return {Status::kOutOfOrderApiCall}; - } - - return current_->RequestConnection(client, endpoint_id, info, options); -} - -Status PcpManager::AcceptConnection(ClientProxy* client, - const string& endpoint_id, - const PayloadListener& payload_listener) { - if (!current_) { - return {Status::kOutOfOrderApiCall}; - } - - return current_->AcceptConnection(client, endpoint_id, payload_listener); -} - -Status PcpManager::RejectConnection(ClientProxy* client, - const string& endpoint_id) { - if (!current_) { - return {Status::kOutOfOrderApiCall}; - } - - return current_->RejectConnection(client, endpoint_id); -} - -bool PcpManager::SetCurrentPcpHandler(Strategy strategy) { - current_ = GetPcpHandler(StrategyToPcp(strategy)); - - if (!current_) { - NEARBY_LOG(ERROR, "Failed to set current PCP handler: strategy=%s", - strategy.GetName().c_str()); - } - - return current_; -} - -PcpHandler* PcpManager::GetPcpHandler(Pcp pcp) const { - auto item = handlers_.find(pcp); - return item != handlers_.end() ? item->second.get() : nullptr; -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/pcp_manager.h b/cpp/core_v2/internal/pcp_manager.h deleted file mode 100644 index bb4d9991..00000000 --- a/cpp/core_v2/internal/pcp_manager.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef CORE_V2_INTERNAL_PCP_MANAGER_H_ -#define CORE_V2_INTERNAL_PCP_MANAGER_H_ - -#include - -#include "core_v2/internal/base_pcp_handler.h" -#include "core_v2/internal/bwu_manager.h" -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/endpoint_channel_manager.h" -#include "core_v2/internal/endpoint_manager.h" -#include "core_v2/internal/mediums/mediums.h" -#include "core_v2/listeners.h" -#include "core_v2/options.h" -#include "core_v2/status.h" -#include "core_v2/strategy.h" -#include "platform_v2/public/atomic_boolean.h" -#include "absl/container/flat_hash_map.h" - -namespace location { -namespace nearby { -namespace connections { - -// Manages all known PcpHandler implementations, delegating operations to the -// appropriate one as per the parameters passed in. -// -// This will only ever be used by the OfflineServiceController, which has all -// of its entrypoints invoked serially, so there's no synchronization needed. -// Public method semantics matches definition in the -// https://source.corp.google.com/piper///depot/google3/core_v2/internal/service_controller.h -class PcpManager { - public: - PcpManager(Mediums& mediums, EndpointChannelManager& channel_manager, - EndpointManager& endpoint_manager, BwuManager& bwu_manager); - ~PcpManager(); - - Status StartAdvertising(ClientProxy* client, const string& service_id, - const ConnectionOptions& options, - const ConnectionRequestInfo& info); - void StopAdvertising(ClientProxy* client); - - Status StartDiscovery(ClientProxy* client, const string& service_id, - const ConnectionOptions& options, - DiscoveryListener listener); - void StopDiscovery(ClientProxy* client); - - Status RequestConnection(ClientProxy* client, const string& endpoint_id, - const ConnectionRequestInfo& info, - const ConnectionOptions& options); - Status AcceptConnection(ClientProxy* client, const string& endpoint_id, - const PayloadListener& payload_listener); - Status RejectConnection(ClientProxy* client, const string& endpoint_id); - - proto::connections::Medium GetBandwidthUpgradeMedium(); - void DisconnectFromEndpointManager(); - - private: - bool SetCurrentPcpHandler(Strategy strategy); - PcpHandler* GetPcpHandler(Pcp pcp) const; - - AtomicBoolean shutdown_{false}; - absl::flat_hash_map> handlers_; - PcpHandler* current_ = nullptr; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_PCP_MANAGER_H_ diff --git a/cpp/core_v2/internal/service_controller.h b/cpp/core_v2/internal/service_controller.h deleted file mode 100644 index ce186949..00000000 --- a/cpp/core_v2/internal/service_controller.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef CORE_V2_INTERNAL_SERVICE_CONTROLLER_H_ -#define CORE_V2_INTERNAL_SERVICE_CONTROLLER_H_ - -#include -#include -#include - -#include "core_v2/internal/client_proxy.h" -#include "core_v2/listeners.h" -#include "core_v2/options.h" -#include "core_v2/params.h" -#include "core_v2/payload.h" -#include "core_v2/status.h" - -namespace location { -namespace nearby { -namespace connections { - -// Interface defines the core functionality of Nearby Connections Service. -// -// In every method, ClientProxy* represents the client app which receives -// notifications from Nearby Connections service and forwards them to the app. -// ResultCallback arguments are not provided for this class, because all methods -// are called synchronously. -// The rest of arguments have the same meaning as the corresponding -// methods in the definition of location::nearby::Core API. -// -// See details here: -// https://source.corp.google.com/piper///depot/google3/core_v2/core.h -class ServiceController { - public: - virtual ~ServiceController() = default; - ServiceController() = default; - ServiceController(const ServiceController&) = delete; - ServiceController& operator=(const ServiceController&) = delete; - - // Starts advertising an endpoint for a local app. - virtual Status StartAdvertising(ClientProxy* client, - const std::string& service_id, - const ConnectionOptions& options, - const ConnectionRequestInfo& info) = 0; - virtual void StopAdvertising(ClientProxy* client) = 0; - - virtual Status StartDiscovery(ClientProxy* client, - const std::string& service_id, - const ConnectionOptions& options, - const DiscoveryListener& listener) = 0; - virtual void StopDiscovery(ClientProxy* client) = 0; - - virtual Status RequestConnection(ClientProxy* client, - const std::string& endpoint_id, - const ConnectionRequestInfo& info, - const ConnectionOptions& options) = 0; - virtual Status AcceptConnection(ClientProxy* client, - const std::string& endpoint_id, - const PayloadListener& listener) = 0; - virtual Status RejectConnection(ClientProxy* client, - const std::string& endpoint_id) = 0; - - virtual void InitiateBandwidthUpgrade(ClientProxy* client, - const std::string& endpoint_id) = 0; - - virtual void SendPayload(ClientProxy* client, - const std::vector& endpoint_ids, - Payload payload) = 0; - - virtual Status CancelPayload(ClientProxy* client, Payload::Id payload_id) = 0; - - virtual void DisconnectFromEndpoint(ClientProxy* client, - const std::string& endpoint_id) = 0; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_SERVICE_CONTROLLER_H_ diff --git a/cpp/core_v2/internal/service_controller_router.cc b/cpp/core_v2/internal/service_controller_router.cc deleted file mode 100644 index e5ce4496..00000000 --- a/cpp/core_v2/internal/service_controller_router.cc +++ /dev/null @@ -1,398 +0,0 @@ -#include "core_v2/internal/service_controller_router.h" - -#include -#include -#include - -#include "core_v2/internal/client_proxy.h" -#include "core_v2/listeners.h" -#include "core_v2/options.h" -#include "core_v2/params.h" -#include "core_v2/payload.h" -#include "platform_v2/public/logging.h" -#include "absl/time/clock.h" - -namespace location { -namespace nearby { -namespace connections { - -ServiceControllerRouter::~ServiceControllerRouter() { - NEARBY_LOG(INFO, "ServiceControllerRouter going down."); - - // And make sure that cleanup is the last thing we do. - serializer_.Shutdown(); -} - -void ServiceControllerRouter::StartAdvertising( - ClientProxy* client, absl::string_view service_id, - const ConnectionOptions& options, const ConnectionRequestInfo& info, - const ResultCallback& callback) { - RouteToServiceController([this, client, service_id = std::string(service_id), - options, info, callback]() { - Status status = AcquireServiceControllerForClient(client, options.strategy); - if (!status.Ok()) { - callback.result_cb(status); - return; - } - - if (client->IsAdvertising()) { - callback.result_cb({Status::kAlreadyAdvertising}); - return; - } - - status = service_controller_->StartAdvertising(client, service_id, options, - info); - callback.result_cb(status); - }); -} - -void ServiceControllerRouter::StopAdvertising(ClientProxy* client, - const ResultCallback& callback) { - RouteToServiceController([this, client, callback]() { - if (ClientHasAcquiredServiceController(client) && client->IsAdvertising()) { - service_controller_->StopAdvertising(client); - } - callback.result_cb({Status::kSuccess}); - }); -} - -void ServiceControllerRouter::StartDiscovery(ClientProxy* client, - absl::string_view service_id, - const ConnectionOptions& options, - const DiscoveryListener& listener, - const ResultCallback& callback) { - RouteToServiceController([this, client, service_id = std::string(service_id), - options, listener, callback]() { - Status status = AcquireServiceControllerForClient(client, options.strategy); - if (!status.Ok()) { - callback.result_cb(status); - return; - } - - if (client->IsDiscovering()) { - callback.result_cb({Status::kAlreadyDiscovering}); - return; - } - - status = service_controller_->StartDiscovery(client, service_id, options, - listener); - callback.result_cb(status); - }); -} - -void ServiceControllerRouter::StopDiscovery(ClientProxy* client, - const ResultCallback& callback) { - RouteToServiceController([this, client, callback]() { - if (ClientHasAcquiredServiceController(client) && client->IsDiscovering()) { - service_controller_->StopDiscovery(client); - } - callback.result_cb({Status::kSuccess}); - }); -} - -void ServiceControllerRouter::RequestConnection( - ClientProxy* client, absl::string_view endpoint_id, - const ConnectionRequestInfo& info, const ConnectionOptions& options, - const ResultCallback& callback) { - RouteToServiceController([this, client, - endpoint_id = std::string(endpoint_id), info, - options, callback]() { - if (!ClientHasAcquiredServiceController(client)) { - callback.result_cb({Status::kOutOfOrderApiCall}); - return; - } - - if (client->HasPendingConnectionToEndpoint(endpoint_id) || - client->IsConnectedToEndpoint(endpoint_id)) { - callback.result_cb({Status::kAlreadyConnectedToEndpoint}); - return; - } - - callback.result_cb(service_controller_->RequestConnection( - client, endpoint_id, info, options)); - }); -} - -void ServiceControllerRouter::AcceptConnection(ClientProxy* client, - absl::string_view endpoint_id, - const PayloadListener& listener, - const ResultCallback& callback) { - RouteToServiceController([this, client, - endpoint_id = std::string(endpoint_id), listener, - callback]() { - if (!ClientHasAcquiredServiceController(client)) { - callback.result_cb({Status::kOutOfOrderApiCall}); - return; - } - - if (client->IsConnectedToEndpoint(endpoint_id)) { - callback.result_cb({Status::kAlreadyConnectedToEndpoint}); - return; - } - - if (client->HasLocalEndpointResponded(endpoint_id)) { - NEARBY_LOG(INFO, - "[ServiceControllerRouter:Accept]: Client has local " - "endpoint responded; id=%s", - endpoint_id.c_str()); - callback.result_cb({Status::kOutOfOrderApiCall}); - return; - } - - callback.result_cb( - service_controller_->AcceptConnection(client, endpoint_id, listener)); - }); -} - -void ServiceControllerRouter::RejectConnection(ClientProxy* client, - absl::string_view endpoint_id, - const ResultCallback& callback) { - RouteToServiceController( - [this, client, endpoint_id = std::string(endpoint_id), callback]() { - if (!ClientHasAcquiredServiceController(client)) { - callback.result_cb({Status::kOutOfOrderApiCall}); - return; - } - - if (client->IsConnectedToEndpoint(endpoint_id)) { - callback.result_cb({Status::kAlreadyConnectedToEndpoint}); - return; - } - - if (client->HasLocalEndpointResponded(endpoint_id)) { - NEARBY_LOG(INFO, - "[ServiceControllerRouter:Reject]: Client has local " - "endpoint responded; id=%s", - endpoint_id.c_str()); - callback.result_cb({Status::kOutOfOrderApiCall}); - return; - } - - callback.result_cb( - service_controller_->RejectConnection(client, endpoint_id)); - }); -} - -void ServiceControllerRouter::InitiateBandwidthUpgrade( - ClientProxy* client, absl::string_view endpoint_id, - const ResultCallback& callback) { - RouteToServiceController( - [this, client, endpoint_id = std::string(endpoint_id), callback]() { - if (!ClientHasAcquiredServiceController(client) || - !client->IsConnectedToEndpoint(endpoint_id)) { - callback.result_cb({Status::kOutOfOrderApiCall}); - return; - } - - service_controller_->InitiateBandwidthUpgrade(client, endpoint_id); - - // Operation is triggered; the caller can listen to - // ConnectionListener::OnBandwidthChanged() to determine its success. - callback.result_cb({Status::kSuccess}); - }); -} - -void ServiceControllerRouter::SendPayload( - ClientProxy* client, absl::Span endpoint_ids, - Payload payload, const ResultCallback& callback) { - // Payload is a move-only type. - // We have to capture it by value inside the lambda, and pass it over to - // the executor as an std::function instance. - // Lambda must be copyable, in order ot satisfy std::function<> requirements. - // To make it so, we need Payload wrapped by a copyable wrapper. - // std::shared_ptr<> is used, because it is copyable. - auto shared_payload = std::make_shared(std::move(payload)); - const std::vector endpoints = - std::vector(endpoint_ids.begin(), endpoint_ids.end()); - - RouteToServiceController( - [this, client, shared_payload, endpoints, callback]() { - if (!ClientHasAcquiredServiceController(client)) { - callback.result_cb({Status::kOutOfOrderApiCall}); - return; - } - - if (!ClientHasConnectionToAtLeastOneEndpoint(client, endpoints)) { - callback.result_cb({Status::kEndpointUnknown}); - return; - } - - service_controller_->SendPayload(client, endpoints, - std::move(*shared_payload)); - - // At this point, we've queued up the send Payload request with the - // ServiceController; any further failures (e.g. one of the endpoints is - // unknown, goes away, or otherwise fails) will be returned to the - // client as a PayloadTransferUpdate. - callback.result_cb({Status::kSuccess}); - }); -} - -void ServiceControllerRouter::CancelPayload(ClientProxy* client, - std::uint64_t payload_id, - const ResultCallback& callback) { - RouteToServiceController([this, client, payload_id, callback]() { - if (!ClientHasAcquiredServiceController(client)) { - callback.result_cb({Status::kOutOfOrderApiCall}); - return; - } - - callback.result_cb(service_controller_->CancelPayload(client, payload_id)); - }); -} - -void ServiceControllerRouter::DisconnectFromEndpoint( - ClientProxy* client, absl::string_view endpoint_id, - const ResultCallback& callback) { - RouteToServiceController( - [this, client, endpoint_id = std::string(endpoint_id), callback]() { - if (ClientHasAcquiredServiceController(client)) { - if (!client->IsConnectedToEndpoint(endpoint_id) && - !client->HasPendingConnectionToEndpoint(endpoint_id)) { - callback.result_cb({Status::kOutOfOrderApiCall}); - return; - } - service_controller_->DisconnectFromEndpoint(client, endpoint_id); - callback.result_cb({Status::kSuccess}); - } - }); -} - -void ServiceControllerRouter::StopAllEndpoints(ClientProxy* client, - const ResultCallback& callback) { - RouteToServiceController([this, client, callback]() { - if (ClientHasAcquiredServiceController(client)) { - DoneWithStrategySessionForClient(client); - } - callback.result_cb({Status::kSuccess}); - }); -} - -void ServiceControllerRouter::ClientDisconnecting( - ClientProxy* client, const ResultCallback& callback) { - RouteToServiceController([this, client, callback]() { - if (ClientHasAcquiredServiceController(client)) { - DoneWithStrategySessionForClient(client); - NEARBY_LOG(INFO, - "[ServiceControllerRouter:Disconnect]: Client has completed " - "the client's connection"); - } - callback.result_cb({Status::kSuccess}); - }); -} - -Status ServiceControllerRouter::AcquireServiceControllerForClient( - ClientProxy* client, Strategy strategy) { - if (current_strategy_.IsNone()) { - // Case 1: There is no existing Strategy at all. - - // Set everything up for the first time. - Status status = UpdateCurrentServiceControllerAndStrategy(strategy); - if (!status.Ok()) { - return status; - } - clients_.insert(client); - return {Status::kSuccess}; - } else if (strategy == current_strategy_) { - // Case 2: The existing Strategy matches. - - // The new client just needs to be added to the set of clients using the - // current ServiceController. - clients_.insert(client); - return {Status::kSuccess}; - } else { - // Case 3: The existing Strategy doesn't match. - - // It's only safe for a client to cause a switch if it's the only client - // using the current ServiceController. - bool is_the_only_client_of_service_controller = - clients_.size() == 1 && ClientHasAcquiredServiceController(client); - if (!is_the_only_client_of_service_controller) { - NEARBY_LOG(INFO, - "[ServiceControllerRouter:AcquireServiceControllerForClient]: " - "Client has already active strategy."); - return {Status::kAlreadyHaveActiveStrategy}; - } - - // If the client still has connected endpoints, they must disconnect before - // they can switch. - if (!client->GetConnectedEndpoints().empty()) { - NEARBY_LOG(INFO, - "[ServiceControllerRouter:AcquireServiceControllerForClient]: " - "Client has connected endpoints."); - return {Status::kOutOfOrderApiCall}; - } - - // By this point, it's safe to switch the Strategy and ServiceController - // (and since it's the only client, there's no need to add it to the set of - // clients using the current ServiceController). - return UpdateCurrentServiceControllerAndStrategy(strategy); - } -} - -bool ServiceControllerRouter::ClientHasAcquiredServiceController( - ClientProxy* client) const { - return clients_.contains(client); -} - -void ServiceControllerRouter::ReleaseServiceControllerForClient( - ClientProxy* client) { - clients_.erase(client); - - if (clients_.empty()) { - service_controller_.reset(); - current_strategy_ = Strategy{}; - } -} - -/** Clean up all state for this client. The client is now free to switch - * strategies. */ -void ServiceControllerRouter::DoneWithStrategySessionForClient( - ClientProxy* client) { - // Disconnect from all the connected endpoints tied to this clientProxy. - for (auto& endpoint_id : client->GetPendingConnectedEndpoints()) { - service_controller_->DisconnectFromEndpoint(client, endpoint_id); - } - - for (auto& endpoint_id : client->GetConnectedEndpoints()) { - service_controller_->DisconnectFromEndpoint(client, endpoint_id); - } - - // Stop any advertising and discovery that may be underway due to this - // clientProxy. - service_controller_->StopAdvertising(client); - service_controller_->StopDiscovery(client); - - ReleaseServiceControllerForClient(client); -} - -void ServiceControllerRouter::RouteToServiceController(Runnable runnable) { - serializer_.Execute(std::move(runnable)); -} - -bool ServiceControllerRouter::ClientHasConnectionToAtLeastOneEndpoint( - ClientProxy* client, const std::vector& remote_endpoint_ids) { - for (auto& endpoint_id : remote_endpoint_ids) { - if (client->IsConnectedToEndpoint(endpoint_id)) { - return true; - } - } - return false; -} - -Status ServiceControllerRouter::UpdateCurrentServiceControllerAndStrategy( - Strategy strategy) { - if (!strategy.IsValid()) { - NEARBY_LOG(INFO, "Strategy is not valid."); - return {Status::kError}; - } - - service_controller_.reset(service_controller_factory_()); - current_strategy_ = strategy; - - return {Status::kSuccess}; -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/service_controller_router.h b/cpp/core_v2/internal/service_controller_router.h deleted file mode 100644 index 70e9742a..00000000 --- a/cpp/core_v2/internal/service_controller_router.h +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef CORE_V2_INTERNAL_SERVICE_CONTROLLER_ROUTER_H_ -#define CORE_V2_INTERNAL_SERVICE_CONTROLLER_ROUTER_H_ - -#include -#include -#include - -#include "core_v2/internal/client_proxy.h" -#include "core_v2/internal/service_controller.h" -#include "core_v2/options.h" -#include "core_v2/params.h" -#include "platform_v2/base/runnable.h" -#include "platform_v2/public/single_thread_executor.h" -#include "absl/container/flat_hash_set.h" -#include "absl/strings/string_view.h" -#include "absl/types/span.h" - -namespace location { -namespace nearby { -namespace connections { - -// ServiceControllerRouter: this class is an implementation detail of a -// location::nearby::Core class. The latter delegates all of its activities to -// the former. -// -// All the activities are documented in the public API class: -// https://source.corp.google.com/piper///depot/google3/core_v2/core.h -// -// In every method, ClientProxy* represents the client app which receives -// notifications from Nearby Connections service and forwards them to the app. -// The rest of arguments have the same meaning as the corresponding -// methods in the definition of location::nearby::Core API. -// -// Every activity is handled the same way: -// 1) all the arguments to the call are captured by value; -// 2) the actual processing is scheduled on a private single-threaded executor, -// which makes locking unnecessary, when internal data is being manipulated. -// 3) activity handlers are delegating much of their work to an implementation -// of a ServiceController interface, which does the actual job. -class ServiceControllerRouter { - public: - explicit ServiceControllerRouter(std::function factory) - : service_controller_factory_(std::move(factory)) {} - ~ServiceControllerRouter(); - ServiceControllerRouter(ServiceControllerRouter&&) = default; - ServiceControllerRouter& operator=(ServiceControllerRouter&&) = default; - - void StartAdvertising(ClientProxy* client, absl::string_view service_id, - const ConnectionOptions& options, - const ConnectionRequestInfo& info, - const ResultCallback& callback); - void StopAdvertising(ClientProxy* client, const ResultCallback& callback); - - void StartDiscovery(ClientProxy* client, absl::string_view service_id, - const ConnectionOptions& options, - const DiscoveryListener& listener, - const ResultCallback& callback); - void StopDiscovery(ClientProxy* client, const ResultCallback& callback); - - void RequestConnection(ClientProxy* client, absl::string_view endpoint_id, - const ConnectionRequestInfo& info, - const ConnectionOptions& options, - const ResultCallback& callback); - void AcceptConnection(ClientProxy* client, absl::string_view endpoint_id, - const PayloadListener& listener, - const ResultCallback& callback); - void RejectConnection(ClientProxy* client, absl::string_view endpoint_id, - const ResultCallback& callback); - - void InitiateBandwidthUpgrade(ClientProxy* client, - absl::string_view endpoint_id, - const ResultCallback& callback); - - void SendPayload(ClientProxy* client, - absl::Span endpoint_ids, Payload payload, - const ResultCallback& callback); - void CancelPayload(ClientProxy* client, std::uint64_t payload_id, - const ResultCallback& callback); - - void DisconnectFromEndpoint(ClientProxy* client, - absl::string_view endpoint_id, - const ResultCallback& callback); - void StopAllEndpoints(ClientProxy* client, const ResultCallback& callback); - - void ClientDisconnecting(ClientProxy* client, const ResultCallback& callback); - - private: - friend class ServiceControllerRouterTest; - static bool ClientHasConnectionToAtLeastOneEndpoint( - ClientProxy* client, const std::vector& remote_endpoint_ids); - - void RouteToServiceController(Runnable runnable); - - Status AcquireServiceControllerForClient(ClientProxy* client, - Strategy strategy); - bool ClientHasAcquiredServiceController(ClientProxy* client) const; - void ReleaseServiceControllerForClient(ClientProxy* client); - void DoneWithStrategySessionForClient(ClientProxy* client); - Status UpdateCurrentServiceControllerAndStrategy(Strategy strategy); - - absl::flat_hash_set clients_; - std::function service_controller_factory_; - std::unique_ptr service_controller_; - Strategy current_strategy_; - SingleThreadExecutor serializer_; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_SERVICE_CONTROLLER_ROUTER_H_ diff --git a/cpp/core_v2/internal/wifi_lan_endpoint_channel.cc b/cpp/core_v2/internal/wifi_lan_endpoint_channel.cc deleted file mode 100644 index a2623a38..00000000 --- a/cpp/core_v2/internal/wifi_lan_endpoint_channel.cc +++ /dev/null @@ -1,48 +0,0 @@ -#include "core_v2/internal/wifi_lan_endpoint_channel.h" - -#include - -#include "platform_v2/public/logging.h" -#include "platform_v2/public/wifi_lan.h" - -namespace location { -namespace nearby { -namespace connections { - -namespace { - -OutputStream* GetOutputStreamOrNull(WifiLanSocket& socket) { - if (socket.GetRemoteWifiLanService().IsValid()) - return &socket.GetOutputStream(); - return nullptr; -} - -InputStream* GetInputStreamOrNull(WifiLanSocket& socket) { - if (socket.GetRemoteWifiLanService().IsValid()) - return &socket.GetInputStream(); - return nullptr; -} - -} // namespace - -WifiLanEndpointChannel::WifiLanEndpointChannel(const std::string& channel_name, - WifiLanSocket socket) - : BaseEndpointChannel(channel_name, GetInputStreamOrNull(socket), - GetOutputStreamOrNull(socket)), - wifi_lan_socket_(std::move(socket)) {} - -proto::connections::Medium WifiLanEndpointChannel::GetMedium() const { - return proto::connections::Medium::WIFI_LAN; -} - -void WifiLanEndpointChannel::CloseImpl() { - auto status = wifi_lan_socket_.Close(); - if (!status.Ok()) { - NEARBY_LOG(INFO, "Failed to close WifiLan socket: exception=%d", - status.value); - } -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/wifi_lan_endpoint_channel.h b/cpp/core_v2/internal/wifi_lan_endpoint_channel.h deleted file mode 100644 index 52cb6564..00000000 --- a/cpp/core_v2/internal/wifi_lan_endpoint_channel.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef CORE_V2_INTERNAL_WIFI_LAN_ENDPOINT_CHANNEL_H_ -#define CORE_V2_INTERNAL_WIFI_LAN_ENDPOINT_CHANNEL_H_ - -#include "core_v2/internal/base_endpoint_channel.h" -#include "platform_v2/public/wifi_lan.h" -#include "proto/connections_enums.pb.h" - -namespace location { -namespace nearby { -namespace connections { - -class WifiLanEndpointChannel final : public BaseEndpointChannel { - public: - // Creates both outgoing and incoming WifiLan channels. - WifiLanEndpointChannel(const std::string& channel_name, - WifiLanSocket socket); - - proto::connections::Medium GetMedium() const override; - - private: - void CloseImpl() override; - - WifiLanSocket wifi_lan_socket_; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_WIFI_LAN_ENDPOINT_CHANNEL_H_ diff --git a/cpp/core_v2/internal/wifi_lan_service_info.cc b/cpp/core_v2/internal/wifi_lan_service_info.cc deleted file mode 100644 index b982a89c..00000000 --- a/cpp/core_v2/internal/wifi_lan_service_info.cc +++ /dev/null @@ -1,194 +0,0 @@ -#include "core_v2/internal/wifi_lan_service_info.h" - -#include - -#include -#include - -#include "platform_v2/base/base64_utils.h" -#include "platform_v2/base/base_input_stream.h" -#include "platform_v2/public/logging.h" -#include "absl/strings/str_cat.h" - -namespace location { -namespace nearby { -namespace connections { - -WifiLanServiceInfo::WifiLanServiceInfo(Version version, Pcp pcp, - absl::string_view endpoint_id, - const ByteArray& service_id_hash, - const ByteArray& endpoint_info, - const ByteArray& uwb_address, - WebRtcState web_rtc_state) { - if (version != Version::kV1 || endpoint_id.empty() || - endpoint_id.length() != kEndpointIdLength || - service_id_hash.size() != kServiceIdHashLength) { - return; - } - switch (pcp) { - case Pcp::kP2pCluster: // Fall through - case Pcp::kP2pStar: // Fall through - case Pcp::kP2pPointToPoint: - break; - default: - return; - } - - version_ = version; - pcp_ = pcp; - service_id_hash_ = service_id_hash; - endpoint_id_ = std::string(endpoint_id); - endpoint_info_ = endpoint_info; - uwb_address_ = uwb_address; - web_rtc_state_ = web_rtc_state; -} - -WifiLanServiceInfo::WifiLanServiceInfo(absl::string_view service_info_string) { - ByteArray service_info_bytes = Base64Utils::Decode(service_info_string); - - if (service_info_bytes.Empty()) { - NEARBY_LOG( - INFO, - "Cannot deserialize WifiLanServiceInfo: failed Base64 decoding of %s", - std::string(service_info_string).c_str()); - return; - } - - if (service_info_bytes.size() < kMinLanServiceNameLength) { - NEARBY_LOG(INFO, - "Cannot deserialize WifiLanServiceInfo: expecting min %d raw " - "bytes, got %" PRIu64, - kMinLanServiceNameLength, service_info_bytes.size()); - return; - } - - if (service_info_bytes.size() > kMaxEndpointInfoLength) { - NEARBY_LOG(INFO, - "Cannot deserialize WifiLanServiceInfo: expecting max %d raw " - "bytes, got %" PRIu64, - kMaxEndpointInfoLength, service_info_bytes.size()); - return; - } - - BaseInputStream base_input_stream{service_info_bytes}; - // The first 1 byte is supposed to be the version and pcp. - auto version_and_pcp_byte = static_cast(base_input_stream.ReadUint8()); - // The upper 3 bits are supposed to be the version. - version_ = - static_cast((version_and_pcp_byte & kVersionBitmask) >> 5); - if (version_ != Version::kV1) { - NEARBY_LOG(INFO, - "Cannot deserialize WifiLanServiceInfo: unsupported Version %d", - version_); - return; - } - // The lower 5 bits are supposed to be the Pcp. - pcp_ = static_cast(version_and_pcp_byte & kPcpBitmask); - switch (pcp_) { - case Pcp::kP2pCluster: // Fall through - case Pcp::kP2pStar: // Fall through - case Pcp::kP2pPointToPoint: - break; - default: - NEARBY_LOG(INFO, - "Cannot deserialize WifiLanServiceInfo: unsupported V1 PCP %d", - pcp_); - } - - // The next 4 bytes are supposed to be the endpoint_id. - endpoint_id_ = std::string{base_input_stream.ReadBytes(kEndpointIdLength)}; - - // The next 3 bytes are supposed to be the service_id_hash. - service_id_hash_ = base_input_stream.ReadBytes(kServiceIdHashLength); - - // The next 1 byte are supposed to be the length of the UWB address. - std::uint32_t expected_uwb_address_length = base_input_stream.ReadUint8(); - - // The next bytes are supposed to be UWB address if length is not zero. - if (expected_uwb_address_length != 0) { - uwb_address_ = base_input_stream.ReadBytes(expected_uwb_address_length); - } - - // The next 1 byte is extra field. - auto extra_field = static_cast(base_input_stream.ReadUint8()); - web_rtc_state_ = (extra_field & kWebRtcConnectableFlagBitmask) == 1 - ? WebRtcState::kConnectable - : WebRtcState::kUnconnectable; - - // The next 1 byte are supposed to be the length of the endpoint_info. - std::uint32_t expected_endpoint_info_length = base_input_stream.ReadUint8(); - - // The rest bytes are supposed to be the endpoint_info - endpoint_info_ = base_input_stream.ReadBytes(expected_endpoint_info_length); - if (endpoint_info_.Empty() || - endpoint_info_.size() != expected_endpoint_info_length) { - NEARBY_LOG(INFO, - "Cannot deserialize WifiLanServiceInfo: expected " - "endpoint info to be %d bytes, got %" PRIu64, - expected_endpoint_info_length, endpoint_info_.size()); - - // Clear enpoint_id for validadity. - endpoint_id_.clear(); - return; - } -} - -WifiLanServiceInfo::operator std::string() const { - if (!IsValid()) { - return ""; - } - - // The upper 3 bits are the Version. - auto version_and_pcp_byte = static_cast( - (static_cast(Version::kV1) << 5) & kVersionBitmask); - // The lower 5 bits are the PCP. - version_and_pcp_byte |= - static_cast(static_cast(pcp_) & kPcpBitmask); - - // A byte contains WebRtcState state. - int web_rtc_connectable_flag = - (web_rtc_state_ == WebRtcState::kConnectable) ? 1 : 0; - char field_byte = static_cast(web_rtc_connectable_flag) & - kWebRtcConnectableFlagBitmask; - - ByteArray usable_endpoint_info(endpoint_info_); - if (endpoint_info_.size() > kMaxEndpointInfoLength) { - NEARBY_LOG( - INFO, - "While serializing WifiLanServiceInfo, truncating Endpoint info %s " - "(%lu bytes) down to %d bytes", - std::string(endpoint_info_).c_str(), endpoint_info_.size(), - kMaxEndpointInfoLength); - usable_endpoint_info.SetData(endpoint_info_.data(), kMaxEndpointInfoLength); - } - - std::string out; - if (!uwb_address_.Empty()) { - // clang-format off - out = absl::StrCat(std::string(1, version_and_pcp_byte), - endpoint_id_, - std::string(service_id_hash_), - std::string(1, uwb_address_.size()), - std::string(uwb_address_), - std::string(1, field_byte), - std::string(1, usable_endpoint_info.size()), - std::string(usable_endpoint_info)); - // clang-format on - } else { - // clang-format off - out = absl::StrCat(std::string(1, version_and_pcp_byte), - endpoint_id_, - std::string(service_id_hash_), - std::string(1, uwb_address_.size()), - std::string(1, field_byte), - std::string(1, usable_endpoint_info.size()), - std::string(usable_endpoint_info)); - // clang-format on - } - - return Base64Utils::Encode(ByteArray{std::move(out)}); -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/internal/wifi_lan_service_info.h b/cpp/core_v2/internal/wifi_lan_service_info.h deleted file mode 100644 index bc422f08..00000000 --- a/cpp/core_v2/internal/wifi_lan_service_info.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef CORE_V2_INTERNAL_WIFI_LAN_SERVICE_INFO_H_ -#define CORE_V2_INTERNAL_WIFI_LAN_SERVICE_INFO_H_ - -#include - -#include "core_v2/internal/base_pcp_handler.h" -#include "core_v2/internal/pcp.h" -#include "platform_v2/base/byte_array.h" -#include "absl/strings/string_view.h" - -namespace location { -namespace nearby { -namespace connections { - -// Represents the format of the WifiLan service info used in Advertising + -// Discovery. -// -// See go/nearby-offline-data-interchange-formats for the specification. -class WifiLanServiceInfo { - public: - // Versions of the WifiLanServiceInfo. - enum class Version { - kUndefined = 0, - kV1 = 1, - }; - - static constexpr std::uint32_t kServiceIdHashLength = 3; - - WifiLanServiceInfo() = default; - WifiLanServiceInfo(Version version, Pcp pcp, absl::string_view endpoint_id, - const ByteArray& service_id_hash, - const ByteArray& endpoint_info, - const ByteArray& uwb_address, - WebRtcState web_rtc_state); - explicit WifiLanServiceInfo(absl::string_view service_info_string); - WifiLanServiceInfo(const WifiLanServiceInfo&) = default; - WifiLanServiceInfo& operator=(const WifiLanServiceInfo&) = default; - WifiLanServiceInfo(WifiLanServiceInfo&&) = default; - WifiLanServiceInfo& operator=(WifiLanServiceInfo&&) = default; - ~WifiLanServiceInfo() = default; - - explicit operator std::string() const; - - bool IsValid() const { return !endpoint_id_.empty(); } - Version GetVersion() const { return version_; } - Pcp GetPcp() const { return pcp_; } - std::string GetEndpointId() const { return endpoint_id_; } - ByteArray GetEndpointInfo() const { return endpoint_info_; } - ByteArray GetServiceIdHash() const { return service_id_hash_; } - ByteArray GetUwbAddress() const { return uwb_address_; } - WebRtcState GetWebRtcState() const { return web_rtc_state_; } - - private: - static constexpr int kMinLanServiceNameLength = 9; - static constexpr int kEndpointIdLength = 4; - static constexpr int kMaxEndpointInfoLength = 131; - static constexpr int kUwbAddressLengthSize = 1; - - static constexpr int kVersionBitmask = 0x0E0; - static constexpr int kPcpBitmask = 0x01F; - static constexpr int kVersionShift = 5; - static constexpr int kWebRtcConnectableFlagBitmask = 0x01; - - Version version_{Version::kUndefined}; - Pcp pcp_{Pcp::kUnknown}; - std::string endpoint_id_; - ByteArray service_id_hash_; - ByteArray endpoint_info_; - // TODO(b/169550050): Define UWB address field. - ByteArray uwb_address_; - WebRtcState web_rtc_state_{WebRtcState::kUndefined}; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_INTERNAL_WIFI_LAN_SERVICE_INFO_H_ diff --git a/cpp/core_v2/internal/wifi_lan_service_info_test.cc b/cpp/core_v2/internal/wifi_lan_service_info_test.cc deleted file mode 100644 index 4eabc78e..00000000 --- a/cpp/core_v2/internal/wifi_lan_service_info_test.cc +++ /dev/null @@ -1,174 +0,0 @@ -#include "core_v2/internal/wifi_lan_service_info.h" - -#include -#include - -#include "platform_v2/base/base64_utils.h" -#include "gtest/gtest.h" - -namespace location { -namespace nearby { -namespace connections { -namespace { - -constexpr WifiLanServiceInfo::Version kVersion = - WifiLanServiceInfo::Version::kV1; -constexpr Pcp kPcp = Pcp::kP2pCluster; -constexpr absl::string_view kEndPointID{"AB12"}; -constexpr absl::string_view kServiceIDHashBytes{"\x0a\x0b\x0c"}; -constexpr absl::string_view kEndPointName{"RAWK + ROWL!"}; -constexpr WebRtcState kWebRtcState = WebRtcState::kConnectable; - -// TODO(b/169550050): Implement UWBAddress. -TEST(WifiLanServiceInfoTest, ConstructionWorks) { - ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; - ByteArray endpoint_info{std::string(kEndPointName)}; - WifiLanServiceInfo wifi_lan_service_info{kVersion, - kPcp, - kEndPointID, - service_id_hash, - endpoint_info, - ByteArray{}, - kWebRtcState}; - - EXPECT_TRUE(wifi_lan_service_info.IsValid()); - EXPECT_EQ(kPcp, wifi_lan_service_info.GetPcp()); - EXPECT_EQ(kVersion, wifi_lan_service_info.GetVersion()); - EXPECT_EQ(kEndPointID, wifi_lan_service_info.GetEndpointId()); - EXPECT_EQ(service_id_hash, wifi_lan_service_info.GetServiceIdHash()); - EXPECT_EQ(endpoint_info, wifi_lan_service_info.GetEndpointInfo()); -} - -TEST(WifiLanServiceInfoTest, ConstructionFromSerializedStringWorks) { - ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; - ByteArray endpoint_info{std::string(kEndPointName)}; - WifiLanServiceInfo org_wifi_lan_service_info{kVersion, - kPcp, - kEndPointID, - service_id_hash, - endpoint_info, - ByteArray{}, - kWebRtcState}; - std::string wifi_lan_service_info_string{org_wifi_lan_service_info}; - - WifiLanServiceInfo wifi_lan_service_info{wifi_lan_service_info_string}; - - EXPECT_TRUE(wifi_lan_service_info.IsValid()); - EXPECT_EQ(kPcp, wifi_lan_service_info.GetPcp()); - EXPECT_EQ(kVersion, wifi_lan_service_info.GetVersion()); - EXPECT_EQ(kEndPointID, wifi_lan_service_info.GetEndpointId()); - EXPECT_EQ(service_id_hash, wifi_lan_service_info.GetServiceIdHash()); - EXPECT_EQ(endpoint_info, wifi_lan_service_info.GetEndpointInfo()); - EXPECT_EQ(kWebRtcState, wifi_lan_service_info.GetWebRtcState()); -} - -TEST(WifiLanServiceInfoTest, ConstructionFailsWithBadVersion) { - auto bad_version = static_cast(666); - - ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; - ByteArray endpoint_info{std::string(kEndPointName)}; - WifiLanServiceInfo wifi_lan_service_info{bad_version, - kPcp, - kEndPointID, - service_id_hash, - endpoint_info, - ByteArray{}, - kWebRtcState}; - - EXPECT_FALSE(wifi_lan_service_info.IsValid()); -} - -TEST(WifiLanServiceInfoTest, ConstructionFailsWithBadPCP) { - auto bad_pcp = static_cast(666); - - ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; - ByteArray endpoint_info{std::string(kEndPointName)}; - WifiLanServiceInfo wifi_lan_service_info{kVersion, - bad_pcp, - kEndPointID, - service_id_hash, - endpoint_info, - ByteArray{}, - kWebRtcState}; - - EXPECT_FALSE(wifi_lan_service_info.IsValid()); -} - -TEST(WifiLanServiceInfoTest, ConstructionFailsWithShortEndpointId) { - std::string short_endpoint_id("AB1"); - - ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; - ByteArray endpoint_info{std::string(kEndPointName)}; - WifiLanServiceInfo wifi_lan_service_info{kVersion, - kPcp, - short_endpoint_id, - service_id_hash, - endpoint_info, - ByteArray{}, - kWebRtcState}; - - EXPECT_FALSE(wifi_lan_service_info.IsValid()); -} - -TEST(WifiLanServiceInfoTest, ConstructionFailsWithLongEndpointId) { - std::string long_endpoint_id("AB12X"); - - ByteArray service_id_hash{std::string(kServiceIDHashBytes)}; - ByteArray endpoint_info{std::string(kEndPointName)}; - WifiLanServiceInfo wifi_lan_service_info{kVersion, - kPcp, - long_endpoint_id, - service_id_hash, - endpoint_info, - ByteArray{}, - kWebRtcState}; - - EXPECT_FALSE(wifi_lan_service_info.IsValid()); -} - -TEST(WifiLanServiceInfoTest, ConstructionFailsWithShortServiceIdHash) { - char short_service_id_hash_bytes[] = "\x0a\x0b"; - - ByteArray short_service_id_hash{short_service_id_hash_bytes}; - ByteArray endpoint_info{std::string(kEndPointName)}; - WifiLanServiceInfo wifi_lan_service_info{kVersion, - kPcp, - kEndPointID, - short_service_id_hash, - endpoint_info, - ByteArray{}, - kWebRtcState}; - - EXPECT_FALSE(wifi_lan_service_info.IsValid()); -} - -TEST(WifiLanServiceInfoTest, ConstructionFailsWithLongServiceIdHash) { - char long_service_id_hash_bytes[] = "\x0a\x0b\x0c\x0d"; - - ByteArray long_service_id_hash{long_service_id_hash_bytes}; - ByteArray endpoint_info{std::string(kEndPointName)}; - WifiLanServiceInfo wifi_lan_service_info{kVersion, - kPcp, - kEndPointID, - long_service_id_hash, - endpoint_info, - ByteArray{}, - kWebRtcState}; - - EXPECT_FALSE(wifi_lan_service_info.IsValid()); -} - -TEST(WifiLanServiceInfoTest, ConstructionFailsWithShortStringLength) { - char wifi_lan_service_info_string[] = {'X', '\0'}; - - ByteArray wifi_lan_service_info_bytes{wifi_lan_service_info_string}; - WifiLanServiceInfo wifi_lan_service_info{ - Base64Utils::Encode(wifi_lan_service_info_bytes)}; - - EXPECT_FALSE(wifi_lan_service_info.IsValid()); -} - -} // namespace -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/listeners.h b/cpp/core_v2/listeners.h deleted file mode 100644 index c58e5413..00000000 --- a/cpp/core_v2/listeners.h +++ /dev/null @@ -1,178 +0,0 @@ -#ifndef CORE_V2_LISTENERS_H_ -#define CORE_V2_LISTENERS_H_ - -#include -#include -#include -#include - -// This file defines all the protocol listeners and their parameter structures. -// Listeners are defined as collections of std::function instances, which is -// more flexible than a virtual function: -// - a subset of listener callbacks may be overridden, while others may remain -// default-initialized. -// - callbacks may be initialized with lambdas; lambda definitions are concize. - -#include "core_v2/options.h" -#include "core_v2/payload.h" -#include "core_v2/status.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/listeners.h" - -namespace location { -namespace nearby { -namespace connections { - -// Common callback for asynchronously invoked methods. -// Called after a job scheduled for execution is completed. -// This is not the same as completion of the associated process, -// which may have many states, and multiple async jobs, and be still ongoing. -// Progress on the overall process is reported by the associated listener. -struct ResultCallback { - // Callback to access the status of the operation when available. - // status - result of job execution; - // Status::kSuccess, if successful; anything else indicates failure. - std::function result_cb = DefaultCallback(); -}; - -struct ConnectionResponseInfo { - ByteArray remote_endpoint_info; - std::string authentication_token; - ByteArray raw_authentication_token; - bool is_incoming_connection = false; - bool is_connection_verified = false; -}; - -struct PayloadProgressInfo { - std::int64_t payload_id = 0; - enum class Status { - kSuccess, - kFailure, - kInProgress, - kCanceled, - } status = Status::kSuccess; - std::int64_t total_bytes = 0; - std::int64_t bytes_transferred = 0; -}; - -enum class DistanceInfo { - kUnknown = 1, - kVeryClose = 2, - kClose = 3, - kFar = 4, -}; - -struct ConnectionListener { - // A basic encrypted channel has been created between you and the endpoint. - // Both sides are now asked if they wish to accept or reject the connection - // before any data can be sent over this channel. - // - // This is your chance, before you accept the connection, to confirm that you - // connected to the correct device. Both devices are given an identical token; - // it's up to you to decide how to verify it before proceeding. Typically this - // involves showing the token on both devices and having the users manually - // compare and confirm; however, this is only required if you desire a secure - // connection between the devices. - // - // Whichever route you decide to take (including not authenticating the other - // device), call Core::AcceptConnection() when you're ready to talk, or - // Core::RejectConnection() to close the connection. - // - // endpoint_id - The identifier for the remote endpoint. - // info - Other relevant information about the connection. - std::function - initiated_cb = - DefaultCallback(); - - // Called after both sides have accepted the connection. - // Both sides may now send Payloads to each other. - // Call Core::SendPayload() or wait for incoming PayloadListener::OnPayload(). - // - // endpoint_id - The identifier for the remote endpoint. - std::function accepted_cb = - DefaultCallback(); - - // Called when either side rejected the connection. - // Payloads can not be exchaged. Call Core::DisconnectFromEndpoint() - // to terminate connection. - // - // endpoint_id - The identifier for the remote endpoint. - std::function - rejected_cb = DefaultCallback(); - - // Called when a remote endpoint is disconnected or has become unreachable. - // At this point service (re-)discovery may start again. - // - // endpoint_id - The identifier for the remote endpoint. - std::function disconnected_cb = - DefaultCallback(); - - // Called when the connection's available bandwidth has changed. - // - // endpoint_id - The identifier for the remote endpoint. - // medium - Medium we upgraded to. - std::function - bandwidth_changed_cb = DefaultCallback(); -}; - -struct DiscoveryListener { - // Called when a remote endpoint is discovered. - // - // endpoint_id - The ID of the remote endpoint that was discovered. - // endpoint_info - The info of the remote endpoint representd by ByteArray. - // service_id - The ID of the service advertised by the remote endpoint. - std::function - endpoint_found_cb = DefaultCallback(); - - // Called when a remote endpoint is no longer discoverable; only called for - // endpoints that previously had been passed to {@link - // #onEndpointFound(String, DiscoveredEndpointInfo)}. - // - // endpoint_id - The ID of the remote endpoint that was lost. - std::function endpoint_lost_cb = - DefaultCallback(); - - // Called when a remote endpoint is found with an updated distance. - // - // arguments: - // endpoint_id - The ID of the remote endpoint that was lost. - // info - The distance info, encoded as enum value. - std::function - endpoint_distance_changed_cb = - DefaultCallback(); -}; - -struct PayloadListener { - // Called when a Payload is received from a remote endpoint. Depending - // on the type of the Payload, all of the data may or may not have been - // received at the time of this call. Use OnPayloadProgress() to - // get updates on the status of the data received. - // - // endpoint_id - The identifier for the remote endpoint that sent the - // payload. - // payload - The Payload object received. - std::function - payload_cb = DefaultCallback(); - - // Called with progress information about an active Payload transfer, either - // incoming or outgoing. - // - // endpoint_id - The identifier for the remote endpoint that is sending or - // receiving this payload. - // info - The PayloadProgressInfo structure describing the status of - // the transfer. - std::function - payload_progress_cb = - DefaultCallback(); -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_LISTENERS_H_ diff --git a/cpp/core_v2/options.h b/cpp/core_v2/options.h deleted file mode 100644 index 94c72f39..00000000 --- a/cpp/core_v2/options.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef CORE_V2_OPTIONS_H_ -#define CORE_V2_OPTIONS_H_ - -#include "core_v2/strategy.h" -#include "platform_v2/base/byte_array.h" -#include "proto/connections_enums.pb.h" -#include "proto/connections_enums.pb.h" - -namespace location { -namespace nearby { -namespace connections { - -using Medium = ::location::nearby::proto::connections::Medium; - -// Generic type: allows definition of a feature T for every Medium. -template -struct MediumSelector { - T bluetooth; - T ble; - T web_rtc; - T wifi_lan; - - constexpr MediumSelector() = default; - constexpr MediumSelector(const MediumSelector&) = default; - constexpr MediumSelector& operator=(const MediumSelector&) = default; - - constexpr bool Any(T value) const { - return bluetooth == value || ble == value || web_rtc == value || - wifi_lan == value; - } - - constexpr bool All(T value) const { - return bluetooth == value && ble == value && web_rtc == value && - wifi_lan == value; - } - - constexpr int Count(T value) const { - int count = 0; - if (bluetooth == value) count++; - if (ble == value) count++; - if (wifi_lan == value) count++; - if (web_rtc == value) count++; - return count; - } - - constexpr MediumSelector& SetAll(T value) { - bluetooth = value; - ble = value; - web_rtc = value; - wifi_lan = value; - return *this; - } - - std::vector GetMediums(T value) const { - std::vector mediums; - // Mediums are sorted in order of decreasing preference. - if (wifi_lan == value) mediums.push_back(Medium::WIFI_LAN); - if (web_rtc == value) mediums.push_back(Medium::WEB_RTC); - if (bluetooth == value) mediums.push_back(Medium::BLUETOOTH); - if (ble == value) mediums.push_back(Medium::BLE); - return mediums; - } -}; - -// Feature On/Off switch for mediums. -using BooleanMediumSelector = MediumSelector; - -// Represents the various power levels that can be used, on mediums that support -// it. -enum class PowerLevel { - kHighPower = 0, - kLowPower = 1, -}; - -// Connection Options: used for both Advertising and Discovery. -// All fields are mutable, to make the type copy-assignable. -struct ConnectionOptions { - Strategy strategy; - BooleanMediumSelector allowed{BooleanMediumSelector().SetAll(true)}; - bool auto_upgrade_bandwidth; - bool enforce_topology_constraints; - bool low_power; - bool enable_bluetooth_listening; - ByteArray remote_bluetooth_mac_address; - std::string fast_advertisement_service_uuid; - // Verify if ConnectionOptions is in a not-initialized (Empty) state. - bool Empty() const { return strategy.IsNone(); } - // Bring ConnectionOptions to a not-initialized (Empty) state. - void Clear() { strategy.Clear(); } - // Returns a copy, but if no mediums are allowed, allowes all mediums. - ConnectionOptions CompatibleOptions() const { - ConnectionOptions result = *this; - if (!allowed.Any(true)) { - result.allowed.SetAll(true); - } - return result; - } - std::vector GetMediums() const { return allowed.GetMediums(true); } -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_OPTIONS_H_ diff --git a/cpp/core_v2/params.h b/cpp/core_v2/params.h deleted file mode 100644 index 2cbc89b7..00000000 --- a/cpp/core_v2/params.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef CORE_V2_PARAMS_H_ -#define CORE_V2_PARAMS_H_ - -#include - -#include "core_v2/listeners.h" -#include "platform_v2/base/byte_array.h" - -namespace location { -namespace nearby { -namespace connections { - -// Used by Discovery in Core::RequestConnection(). -// Used by Advertising in Core::StartAdvertising(). -struct ConnectionRequestInfo { - // endpoint_info - Identifing information about this endpoint (eg. name, - // device type). - // listener - A set of callbacks notified when remote endpoints request a - // connection to this endpoint. - ByteArray endpoint_info; - ConnectionListener listener; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_PARAMS_H_ diff --git a/cpp/core_v2/payload.h b/cpp/core_v2/payload.h deleted file mode 100644 index 30bff4af..00000000 --- a/cpp/core_v2/payload.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef CORE_V2_PAYLOAD_H_ -#define CORE_V2_PAYLOAD_H_ - -#include -#include -#include -#include - -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/input_stream.h" -#include "platform_v2/base/payload_id.h" -#include "platform_v2/base/prng.h" -#include "platform_v2/public/file.h" -#include "absl/types/variant.h" - -namespace location { -namespace nearby { -namespace connections { - -// Payload is default-constructible, and moveable, but not copyable container -// that holds at most one instance of one of: -// ByteArray, InputStream, or InputFile. -class Payload { - public: - using Id = PayloadId; - // Order of types in variant, and values in Type enum is important. - // Enum values must match respective variant types. - using Content = absl::variant, InputFile>; - enum class Type { kUnknown = 0, kBytes = 1, kStream = 2, kFile = 3 }; - - Payload(Payload&& other) = default; - ~Payload() = default; - Payload& operator=(Payload&& other) = default; - - // Default (invalid) payload. - Payload() : content_(absl::monostate()) {} - - // Constructors for outgoing payloads. - explicit Payload(ByteArray&& bytes) : content_(std::move(bytes)) {} - explicit Payload(const ByteArray& bytes) : content_(bytes) {} - explicit Payload(std::function stream) - : content_(std::move(stream)) {} - - // Constructors for incoming payloads. - Payload(Id id, ByteArray&& bytes) : content_(std::move(bytes)), id_(id) {} - Payload(Id id, const ByteArray& bytes) : content_(bytes), id_(id) {} - Payload(Id id, std::function stream) - : content_(std::move(stream)), id_(id) {} - - // Constructor for incoming and outgoing file payloads. - Payload(Id id, InputFile file) : content_(std::move(file)), id_(id) {} - - // Returns ByteArray payload, if it has been defined, or empty ByteArray. - const ByteArray& AsBytes() const& { - static const ByteArray empty; // NOLINT: function-level static is OK. - auto* result = absl::get_if(&content_); - return result ? *result : empty; - } - ByteArray&& AsBytes() && { - auto* result = absl::get_if(&content_); - return result ? std::move(*result) : std::move(ByteArray()); - } - // Returns InputStream* payload, if it has been defined, or nullptr. - InputStream* AsStream() { - auto* result = absl::get_if>(&content_); - return result ? &(*result)() : nullptr; - } - // Returns InputFile* payload, if it has been defined, or nullptr. - InputFile* AsFile() { return absl::get_if(&content_); } - - // Returns Payload unique ID. - Id GetId() const { return id_; } - - // Returns Payload type. - Type GetType() const { return type_; } - - // Generate Payload Id; to be passed to outgoing file constructor. - static Id GenerateId() { return Prng().NextInt64(); } - - private: - Type FindType(const Content& content) const { - return static_cast(content_.index()); - } - - Content content_; - Id id_{GenerateId()}; - Type type_{FindType(content_)}; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_PAYLOAD_H_ diff --git a/cpp/core_v2/status.h b/cpp/core_v2/status.h deleted file mode 100644 index c5d49740..00000000 --- a/cpp/core_v2/status.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef CORE_V2_STATUS_H_ -#define CORE_V2_STATUS_H_ - -namespace location { -namespace nearby { -namespace connections { - -// Protocol operation result: kSuccess, if operation was successful; -// descriptive error code otherwise. -struct Status { - // Status is a struct, so it is possible to pass some context about failure, - // by adding extra fields to it when necessary, and not change any of the - // method signatures. - enum Value { - kSuccess, - kError, - kOutOfOrderApiCall, - kAlreadyHaveActiveStrategy, - kAlreadyAdvertising, - kAlreadyDiscovering, - kEndpointIoError, - kEndpointUnknown, - kConnectionRejected, - kAlreadyConnectedToEndpoint, - kNotConnectedToEndpoint, - kBluetoothError, - kBleError, - kWifiLanError, - kPayloadUnknown, - }; - Value value {kError}; - bool Ok() const { return value == kSuccess; } -}; - -inline bool operator==(const Status& a, const Status& b) { - return a.value == b.value; -} - -inline bool operator!=(const Status& a, const Status& b) { - return !(a == b); -} - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_STATUS_H_ diff --git a/cpp/core_v2/strategy.cc b/cpp/core_v2/strategy.cc deleted file mode 100644 index d17a9090..00000000 --- a/cpp/core_v2/strategy.cc +++ /dev/null @@ -1,47 +0,0 @@ -#include "core_v2/strategy.h" - -namespace location { -namespace nearby { -namespace connections { - -const Strategy Strategy::kNone = {Strategy::ConnectionType::kNone, - Strategy::TopologyType::kUnknown}; -const Strategy Strategy::kP2pCluster{Strategy::ConnectionType::kPointToPoint, - Strategy::TopologyType::kManyToMany}; -const Strategy Strategy::kP2pStar{Strategy::ConnectionType::kPointToPoint, - Strategy::TopologyType::kOneToMany}; -const Strategy Strategy::kP2pPointToPoint{ - Strategy::ConnectionType::kPointToPoint, Strategy::TopologyType::kOneToOne}; - -bool Strategy::IsNone() const { - return *this == kNone; -} - -bool Strategy::IsValid() const { - return *this == kP2pStar || *this == kP2pCluster || *this ==kP2pPointToPoint; -} - -std::string Strategy::GetName() const { - if (*this == Strategy::kP2pCluster) { - return "P2P_CLUSTER"; - } else if (*this == Strategy::kP2pStar) { - return "P2P_STAR"; - } else if (*this == Strategy::kP2pPointToPoint) { - return "P2P_POINT_TO_POINT"; - } else { - return "UNKNOWN"; - } -} - -bool operator==(const Strategy& lhs, const Strategy& rhs) { - return lhs.connection_type_ == rhs.connection_type_ && - lhs.topology_type_ == rhs.topology_type_; -} - -bool operator!=(const Strategy& lhs, const Strategy& rhs) { - return !(lhs == rhs); -} - -} // namespace connections -} // namespace nearby -} // namespace location diff --git a/cpp/core_v2/strategy.h b/cpp/core_v2/strategy.h deleted file mode 100644 index 88eb0206..00000000 --- a/cpp/core_v2/strategy.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef CORE_V2_STRATEGY_H_ -#define CORE_V2_STRATEGY_H_ - -#include - -namespace location { -namespace nearby { -namespace connections { - -// Defines a copyable, comparable connection strategy type. -// It is one of: kP2pCluster, kP2pStar, kP2pPointToPoint. -class Strategy { - public: - static const Strategy kNone; - static const Strategy kP2pCluster; - static const Strategy kP2pStar; - static const Strategy kP2pPointToPoint; - - constexpr Strategy() : Strategy(kNone) {} - - constexpr Strategy(const Strategy& other) - : connection_type_(other.connection_type_), - topology_type_(other.topology_type_) {} - - // Returns true, if strategy is kNone, false otherwise. - bool IsNone() const; - // Returns true, if a strategy is one of the supported strategies, - // false otherwise. - bool IsValid() const; - // Returns a string representing given strategy, for every valid strategy. - std::string GetName() const; - // Undefine strategy. - void Clear() { - *this = kNone; - } - - friend bool operator==(const Strategy& lhs, const Strategy& rhs); - friend bool operator!=(const Strategy& lhs, const Strategy& rhs); - - private: - enum class ConnectionType { - kNone = 0, - kPointToPoint = 1, - }; - enum class TopologyType { - kUnknown = 0, - kOneToOne = 1, - kOneToMany = 2, - kManyToMany = 3, - }; - constexpr Strategy(ConnectionType connection_type, TopologyType topology_type) - : connection_type_(connection_type), topology_type_(topology_type) {} - - ConnectionType connection_type_; - TopologyType topology_type_; -}; - -} // namespace connections -} // namespace nearby -} // namespace location - -#endif // CORE_V2_STRATEGY_H_ diff --git a/cpp/platform/BUILD b/cpp/platform/BUILD deleted file mode 100644 index 1ee1d0df..00000000 --- a/cpp/platform/BUILD +++ /dev/null @@ -1,92 +0,0 @@ -cc_library( - name = "utils", - srcs = [ - "base64_utils.cc", - "cancelable_alarm.cc", - "pipe.cc", - "prng.cc", - "reliability_utils.cc", - ], - hdrs = [ - "base64_utils.h", - "cancelable_alarm.h", - "pipe.h", - "prng.h", - "reliability_utils.h", - "synchronized.h", - ], - visibility = [ - "//core:__subpackages__", - "//platform/impl:__subpackages__", - "//location/nearby/setup/core/internal:__subpackages__", - ], - deps = [ - ":types", - "//platform/api", - "//platform/port:string", - "//absl/strings", - "//absl/time", - ], -) - -cc_library( - name = "types", - hdrs = [ - "byte_array.h", - "callable.h", - "cancelable.h", - "container_of.h", - "exception.h", - "ptr.h", - "runnable.h", - ], - visibility = [ - "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", - "//core:__subpackages__", - "//platform:__subpackages__", - "//location/nearby/setup/core:__subpackages__", - ], - deps = [ - ":logging", - "//platform/port:down_cast", - "//platform/port:string", - ], -) - -cc_library( - name = "logging", - hdrs = [ - "logging.h", - ], - visibility = [ - "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", - "//core:__subpackages__", - ], - deps = [ - "//absl/base", - "//absl/base:raw_logging_internal", - ], -) - -cc_test( - name = "platform_test", - timeout = "short", - srcs = [ - "atomic_reference_test.cc", - "byte_array_test.cc", - "container_of_test.cc", - "pipe_test.cc", - "prng_test.cc", - "ptr_test.cc", - "settable_future_test.cc", - ], - deps = [ - ":utils", - "//platform:types", - "//platform/api", - "//platform/impl/g3", - "//platform/port:string", - "//testing/base/public:gunit_main", - "//absl/time", - ], -) diff --git a/cpp/platform/api/BUILD b/cpp/platform/api/BUILD index 62c38942..6eafb5e3 100644 --- a/cpp/platform/api/BUILD +++ b/cpp/platform/api/BUILD @@ -1,69 +1,77 @@ -package(default_visibility = [ - "//core:__subpackages__", - "//platform:__subpackages__", - "//location/nearby/setup/core:__subpackages__", -]) - cc_library( - name = "api", + name = "types", hdrs = [ "atomic_boolean.h", "atomic_reference.h", - "atomic_reference_def.h", + "cancelable.h", + "condition_variable.h", + "count_down_latch.h", + "crypto.h", + "executor.h", + "future.h", + "input_file.h", + "listenable_future.h", + "log_message.h", + "mutex.h", + "output_file.h", + "scheduled_executor.h", + "settable_future.h", + "submittable_executor.h", + "system_clock.h", + ], + visibility = [ + "//platform/base:__pkg__", + "//platform/impl:__subpackages__", + "//platform/public:__pkg__", + ], + deps = [ + "//platform/base", + "//absl/base:core_headers", + "//absl/strings", + "//absl/time", + ], +) + +cc_library( + name = "comm", + hdrs = [ "ble.h", "ble_v2.h", "bluetooth_adapter.h", "bluetooth_classic.h", - "condition_variable.h", - "count_down_latch.h", - "executor.h", - "future.h", - "hash_utils.h", - "input_file.h", - "input_stream.h", - "listenable_future.h", - "lock.h", - "multi_thread_executor.h", - "output_file.h", - "output_stream.h", - "platform.h", - "scheduled_executor.h", "server_sync.h", - "settable_future.h", - "settable_future_def.h", - "single_thread_executor.h", - "socket.h", - "submittable_executor.h", - "submittable_executor_def.h", - "system_clock.h", - "thread_utils.h", "webrtc.h", "wifi.h", "wifi_lan.h", ], + visibility = [ + "//platform/base:__pkg__", + "//platform/impl:__subpackages__", + "//platform/public:__pkg__", + ], deps = [ - "//platform:types", - "//platform/port:down_cast", - "//platform/port:string", + "//proto/connections:offline_wire_formats_portable_proto", + "//platform/base", "//absl/strings", - "//absl/types:any", + "//absl/types:optional", "//webrtc/api:libjingle_peerconnection_api", ], ) cc_library( - name = "lock", - hdrs = ["lock.h"], + name = "platform", + hdrs = [ + "platform.h", + ], visibility = [ - "//platform:__subpackages__", + "//platform/base:__pkg__", + "//platform/impl:__subpackages__", + "//platform/public:__pkg__", + ], + deps = [ + ":comm", + ":types", + "//platform/base", + "//absl/strings", ], ) - -cc_library( - name = "condition_variable", - hdrs = ["condition_variable.h"], - visibility = [ - "//platform:__subpackages__", - ], - deps = ["//platform:types"], -) diff --git a/cpp/platform/api/atomic_boolean.h b/cpp/platform/api/atomic_boolean.h index 41f94165..56bdde5a 100644 --- a/cpp/platform/api/atomic_boolean.h +++ b/cpp/platform/api/atomic_boolean.h @@ -3,18 +3,21 @@ namespace location { namespace nearby { +namespace api { // A boolean value that may be updated atomically. -// -// https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicBoolean.html class AtomicBoolean { public: - virtual ~AtomicBoolean() {} + virtual ~AtomicBoolean() = default; - virtual bool get() = 0; - virtual void set(bool value) = 0; + // Atomically read and return current value. + virtual bool Get() const = 0; + + // Atomically exchange original value with a new one. Return previous value. + virtual bool Set(bool value) = 0; }; +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform/api/atomic_reference.h b/cpp/platform/api/atomic_reference.h index f06a5e06..27778bf5 100644 --- a/cpp/platform/api/atomic_reference.h +++ b/cpp/platform/api/atomic_reference.h @@ -1,48 +1,25 @@ #ifndef PLATFORM_API_ATOMIC_REFERENCE_H_ #define PLATFORM_API_ATOMIC_REFERENCE_H_ -#include "platform/api/atomic_reference_def.h" -#include "platform/api/platform.h" -#include "platform/ptr.h" -#include "absl/types/any.h" +#include namespace location { namespace nearby { +namespace api { -// "Common" part of implementation. -// Placed here for textual compatibility to minimize scope of changes. -// Can be (and should be) moved to a separate file outside "api" folder. -// TODO(apolyudov): for API v2.0 -namespace platform { -namespace impl { -template -class AtomicReferenceImpl : public AtomicReference { +// Type that allows 32-bit atomic reads and writes. +class AtomicUint32 { public: - explicit AtomicReferenceImpl(T initial_value) { - atomic_ = platform::ImplementationPlatform::createAtomicReferenceAny( - absl::any(initial_value)); - } + virtual ~AtomicUint32() = default; - ~AtomicReferenceImpl() override = default; + // Atomically reads and returns stored value. + virtual std::uint32_t Get() const = 0; - void set(T new_value) override { atomic_->set(absl::any(new_value)); } - - T get() override { return absl::any_cast(atomic_->get()); } - - private: - Ptr> atomic_; + // Atomically stores value. + virtual void Set(std::uint32_t value) = 0; }; -} // namespace impl - -template -Ptr> ImplementationPlatform::createAtomicReference( - T initial_value) { - return Ptr>( - new impl::AtomicReferenceImpl{initial_value}); -} - -} // namespace platform +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform/api/atomic_reference_def.h b/cpp/platform/api/atomic_reference_def.h deleted file mode 100644 index 7133caf8..00000000 --- a/cpp/platform/api/atomic_reference_def.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef PLATFORM_API_ATOMIC_REFERENCE_DEF_H_ -#define PLATFORM_API_ATOMIC_REFERENCE_DEF_H_ - -namespace location { -namespace nearby { - -// An object reference that may be updated atomically. -// -// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReference.html -// -// Platform must implentent non-template static member functions -// Ptr> CreateAtomicReferenceSizeT() -// Ptr>> CreateAtomicReferencePtr() -// in the location::nearby::platform::ImplementationPlatform class. -template -class AtomicReference { - public: - virtual ~AtomicReference() = default; - - virtual T get() = 0; - virtual void set(T value) = 0; -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_API_ATOMIC_REFERENCE_DEF_H_ diff --git a/cpp/platform/api/ble.h b/cpp/platform/api/ble.h index e9d44250..ed1280b5 100644 --- a/cpp/platform/api/ble.h +++ b/cpp/platform/api/ble.h @@ -2,122 +2,107 @@ #define PLATFORM_API_BLE_H_ #include "platform/api/bluetooth_classic.h" -#include "platform/api/input_stream.h" -#include "platform/api/output_stream.h" -#include "platform/byte_array.h" -#include "platform/ptr.h" +#include "platform/base/byte_array.h" +#include "platform/base/input_stream.h" +#include "platform/base/output_stream.h" namespace location { namespace nearby { +namespace api { // Opaque wrapper over a BLE peripheral. Must contain enough data about a // particular BLE device to connect to its GATT server. -class BLEPeripheral { +class BlePeripheral { public: - virtual ~BLEPeripheral() {} + virtual ~BlePeripheral() = default; - // The returned Ptr is not owned by the caller, and can be invalidated once - // the corresponding BLEPeripheral object is destroyed. - virtual Ptr getBluetoothDevice() = 0; + virtual std::string GetName() const = 0; + + virtual ByteArray GetAdvertisementBytes( + const std::string& service_id) const = 0; }; -class BLESocket { +class BleSocket { public: - virtual ~BLESocket() {} + virtual ~BleSocket() = default; - // Returns the InputStream of the BLESocket, or a null Ptr - // on error. + // Returns the InputStream of the BleSocket. + // On error, returned stream will report Exception::kIo on any operation. // - // The returned Ptr is not owned by the caller, and can be invalidated once - // the BLESocket object is destroyed. - virtual Ptr getInputStream() = 0; + // The returned object is not owned by the caller, and can be invalidated once + // the BleSocket object is destroyed. + virtual InputStream& GetInputStream() = 0; - // Returns the OutputStream of the BLESocket, or a null - // Ptr on error. + // Returns the OutputStream of the BleSocket. + // On error, returned stream will report Exception::kIo on any operation. // - // The returned Ptr is not owned by the caller, and can be invalidated once - // the BLESocket object is destroyed. - virtual Ptr getOutputStream() = 0; + // The returned object is not owned by the caller, and can be invalidated once + // the BleSocket object is destroyed. + virtual OutputStream& GetOutputStream() = 0; // Conforms to the same contract as // https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#close(). // - // Returns Exception::IO on error, Exception::NONE otherwise. - virtual Exception::Value close() = 0; + // Returns Exception::kIo on error, Exception::kSuccess otherwise. + virtual Exception Close() = 0; - // The returned Ptr is not owned by the caller, and can be invalidated once - // the BLESocket object is destroyed. - virtual Ptr getRemotePeripheral() = 0; + // Returns valid BlePeripheral pointer if there is a connection, and + // nullptr otherwise. + virtual BlePeripheral* GetRemotePeripheral() = 0; }; // Container of operations that can be performed over the BLE medium. -class BLEMedium { +class BleMedium { public: - virtual ~BLEMedium() {} + virtual ~BleMedium() = default; - // Takes ownership of (and is responsible for destroying) the passed-in - // 'advertisement'. - virtual bool startAdvertising(const std::string& service_id, - ConstPtr advertisement) = 0; - virtual void stopAdvertising(const std::string& service_id) = 0; + virtual bool StartAdvertising( + const std::string& service_id, const ByteArray& advertisement_bytes, + const std::string& fast_advertisement_service_uuid) = 0; + virtual bool StopAdvertising(const std::string& service_id) = 0; - class DiscoveredPeripheralCallback { - public: - virtual ~DiscoveredPeripheralCallback() {} - - // The Ptrs provided in these callback methods will be owned (and - // destroyed) by the recipient of the callback methods (i.e. the creator of - // the concrete DiscoveredPeripheralCallback object). - virtual void onPeripheralDiscovered(Ptr ble_peripheral, - const std::string& service_id, - ConstPtr advertisement) = 0; - virtual void onPeripheralLost(Ptr ble_peripheral, - const std::string& service_id) = 0; + // Callback that is invoked when a discovered peripheral is found or lost. + struct DiscoveredPeripheralCallback { + std::function + peripheral_discovered_cb = + DefaultCallback(); + std::function + peripheral_lost_cb = + DefaultCallback(); }; // Returns true once the BLE scan has been initiated. - // - // Does not take ownership of the passed-in discovered_peripheral_callback -- - // destroying that is up to the caller. - virtual bool startScanning( - const std::string& service_id, - Ptr discovered_peripheral_callback) = 0; + virtual bool StartScanning(const std::string& service_id, + const std::string& fast_advertisement_service_uuid, + DiscoveredPeripheralCallback callback) = 0; + // Returns true once BLE scanning for service_id is well and truly stopped; // after this returns, there must be no more invocations of the - // DiscoveredPeripheralCallback passed in to startScanning() for service_id. - // - // Does not need to bother with destroying the DiscoveredPeripheralCallback - // passed in to startScanning() -- that's the job of the caller. - virtual void stopScanning(const std::string& service_id) = 0; + // DiscoveredPeripheralCallback passed in to StartScanning() for service_id. + virtual bool StopScanning(const std::string& service_id) = 0; // Callback that is invoked when a new connection is accepted. - class AcceptedConnectionCallback { - public: - virtual ~AcceptedConnectionCallback() {} - - // The Ptr provided in this callback method will be owned (and - // destroyed) by the recipient of the callback methods (i.e. the creator of - // the concrete AcceptedConnectionCallback object). - virtual void onConnectionAccepted(Ptr socket, - const std::string& service_id) = 0; + struct AcceptedConnectionCallback { + std::function + accepted_cb = DefaultCallback(); }; // Returns true once BLE socket connection requests to service_id can be // accepted. - // - // Does not take ownership of the passed-in accepted_connection_callback -- - // destroying that is up to the caller. - virtual bool startAcceptingConnections( - const std::string& service_id, - Ptr accepted_connection_callback) = 0; - virtual void stopAcceptingConnections(const std::string& service_id) = 0; + virtual bool StartAcceptingConnections( + const std::string& service_id, AcceptedConnectionCallback callback) = 0; + virtual bool StopAcceptingConnections(const std::string& service_id) = 0; - // The returned Ptr will be owned (and destroyed) by the caller. Returns - // a null Ptr on error. - virtual Ptr connect(Ptr ble_peripheral, - const std::string& service_id) = 0; + // Connects to a BLE peripheral. + // On success, returns a new BleSocket. + // On error, returns nullptr. + virtual std::unique_ptr Connect(BlePeripheral& peripheral, + const std::string& service_id) = 0; }; +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform/api/ble_v2.h b/cpp/platform/api/ble_v2.h index b4353076..110e1487 100644 --- a/cpp/platform/api/ble_v2.h +++ b/cpp/platform/api/ble_v2.h @@ -4,15 +4,19 @@ #include #include #include +#include #include +#include -#include "platform/byte_array.h" -#include "platform/exception.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "platform/base/byte_array.h" +#include "platform/base/exception.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" namespace location { namespace nearby { +namespace api { +namespace ble_v2 { // https://developer.android.com/reference/android/bluetooth/le/AdvertiseData // @@ -21,16 +25,16 @@ namespace nearby { // All service UUIDs will conform to the 16-bit Bluetooth base UUID, // 0000xxxx-0000-1000-8000-00805F9B34FB. This makes it possible to store two // byte service UUIDs in the advertisement. -struct BLEAdvertisementData { - typedef std::int8_t TXPowerLevel; +struct BleAdvertisementData { + using TxPowerLevel = int8_t; - static constexpr TXPowerLevel UNSPECIFIED_TX_POWER_LEVEL = - std::numeric_limits::min(); + static const TxPowerLevel kUnspecifiedTxPowerLevel = + std::numeric_limits::min(); bool is_connectable; - // When set to UNSPECIFIED_TX_POWER_LEVEL, TX power should not be included in + // When set to kUnspecifiedTxPowerLevel, TX power should not be included in // the advertisement data. - TXPowerLevel tx_power_level; + TxPowerLevel tx_power_level; // When set to an empty string, local name should not be included in the // advertisement data. std::string local_name; @@ -38,75 +42,64 @@ struct BLEAdvertisementData { // not be included in the advertisement data. std::set service_uuids; // Maps service UUIDs to their service data. - // Ownership of the map values is tied to ownership of BLEAdvertisementData. - std::map> service_data; + std::map service_data; }; // Opaque wrapper over a BLE peripheral. Must be able to uniquely identify a // peripheral so that we can connect to its GATT server. -// -// BLEPeripheralV2 should always be created as a RefCountedPtr because ownership -// is shared between the per-platform implementation and the internals of Nearby -// Connections. -class BLEPeripheralV2 { +class BlePeripheral { public: - virtual ~BLEPeripheralV2() {} + virtual ~BlePeripheral() {} // https://developer.android.com/reference/android/bluetooth/BluetoothDevice#getAddress() // // This should be the MAC address when possible. If the implementation is // unable to retrieve that, any unique identifier should suffice. - virtual std::string getId() = 0; + virtual std::string GetId() const = 0; }; // https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic // // Representation of a GATT characteristic. -// -// GATTCharacteristics are RefCounted so that ownership can be shared between -// the per-platform implementation and C++ internals. All GATTCharacteristics -// should be created with MakeRefCountedPtr(). -class GATTCharacteristic { +class GattCharacteristic { public: - virtual ~GATTCharacteristic() {} + virtual ~GattCharacteristic() {} // Possible permissions of a GATT characteristic. - struct Permission { - enum Value { - UNKNOWN = 0, - READ = 1, - WRITE = 2, - }; + enum class Permission { + kUnknown = 0, + kRead = 1, + kWrite = 2, + kLast, }; // Possible properties of a GATT characteristic. - struct Property { - enum Value { - UNKNOWN = 0, - READ = 1, - WRITE = 2, - INDICATE = 3, - }; + enum class Property { + kUnknown = 0, + kRead = 1, + kWrite = 2, + kIndicate = 3, + kLast, }; // Returns the UUID of this characteristic. - virtual std::string getUUID() = 0; + virtual std::string GetUuid() = 0; // Returns the UUID of the containing GATT service. - virtual std::string getServiceUUID() = 0; + virtual std::string GetServiceUuid() = 0; }; // https://developer.android.com/reference/android/bluetooth/BluetoothGatt // // Representation of a client GATT connection to a remote GATT server. -class ClientGATTConnection { +class ClientGattConnection { public: - virtual ~ClientGATTConnection() {} + virtual ~ClientGattConnection() {} // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#getDevice() // // Retrieves the BLE peripheral that this connection is tied to. - virtual Ptr getPeripheral() = 0; + virtual BlePeripheral& GetPeripheral() = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#discoverServices() // @@ -114,49 +107,49 @@ class ClientGATTConnection { // Returns whether or not discovery finished successfully. // // This function should block until discovery has finished. - virtual bool discoverServices() = 0; + virtual bool DiscoverServices() = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#getService(java.util.UUID) // https://developer.android.com/reference/android/bluetooth/BluetoothGattService.html#getCharacteristic(java.util.UUID) // - // Retrieves a GATT characteristic. A null Ptr is returned upon error. + // Retrieves a GATT characteristic. On error, does not return a value. // - // discoverServices() should be called before this method to fetch all + // DiscoverServices() should be called before this method to fetch all // available services and characteristics first. // // It is okay for duplicate services to exist, as long as the specified // characteristic UUID is unique among all services of the same UUID. - virtual Ptr getCharacteristic( - const std::string& service_uuid, - const std::string& characteristic_uuid) = 0; + virtual absl::optional GetCharacteristic( + absl::string_view service_uuid, + absl::string_view characteristic_uuid) = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#readCharacteristic(android.bluetooth.BluetoothGattCharacteristic) // https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#getValue() // - // Reads a GATT characteristic. A null ConstPtr is returned upon error. - virtual ConstPtr readCharacteristic( - Ptr characteristic) = 0; + // Reads a GATT characteristic. No value is returned upon error. + virtual absl::optional ReadCharacteristic( + const GattCharacteristic& characteristic) = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#setValue(byte[]) // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic) // // Sends a remote characteristic write request to the server and returns // whether or not it was successful. - virtual bool writeCharacteristic(Ptr characteristic, - ConstPtr value) = 0; + virtual bool WriteCharacteristic(const GattCharacteristic& characteristic, + const ByteArray& value) = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#disconnect() // // Disconnects a GATT connection. - virtual void disconnect() = 0; + virtual void Disconnect() = 0; }; // https://developer.android.com/reference/android/bluetooth/BluetoothGattServer // // Representation of a server GATT connection to a remote GATT client. -class ServerGATTConnection { +class ServerGattConnection { public: - virtual ~ServerGATTConnection() {} + virtual ~ServerGattConnection() {} // https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#setValue(byte[]) // https://developer.android.com/reference/android/bluetooth/BluetoothGattServer.html#notifyCharacteristicChanged(android.bluetooth.BluetoothDevice,%20android.bluetooth.BluetoothGattCharacteristic,%20boolean) @@ -165,47 +158,47 @@ class ServerGATTConnection { // has changed with the given value. Returns whether or not it was successful. // // The value sent does not have to reflect the locally stored characteristic - // value. To update the local value, call GATTServer::updateCharacteristic. - virtual bool sendCharacteristic(Ptr characteristic, - ConstPtr value) = 0; + // value. To update the local value, call GattServer::UpdateCharacteristic. + virtual bool SendCharacteristic(const GattCharacteristic& characteristic, + const ByteArray& value) = 0; }; // Callback for asynchronous events on the client side of a GATT connection. -class ClientGATTConnectionLifecycleCallback { +class ClientGattConnectionLifeCycleCallback { public: - virtual ~ClientGATTConnectionLifecycleCallback() {} + virtual ~ClientGattConnectionLifeCycleCallback() {} // Called when the client is disconnected from the GATT server. - virtual void onDisconnected(Ptr connection) = 0; + virtual void OnDisconnected(ClientGattConnection* connection) = 0; }; // Callback for asynchronous events on the server side of a GATT connection. -class ServerGATTConnectionLifecycleCallback { +class ServerGattConnectionLifeCycleCallback { public: - virtual ~ServerGATTConnectionLifecycleCallback() {} + virtual ~ServerGattConnectionLifeCycleCallback() {} // Called when a remote peripheral connected to us and subscribed to one of // our characteristics. - virtual void onCharacteristicSubscription( - Ptr connection, - Ptr characteristic) = 0; + virtual void OnCharacteristicSubscription( + ServerGattConnection* connection, + const GattCharacteristic& characteristic) = 0; // Called when a remote peripheral unsubscribed from one of our // characteristics. - virtual void onCharacteristicUnsubscription( - Ptr connection, - Ptr characteristic) = 0; + virtual void OnCharacteristicUnsubscription( + ServerGattConnection* connection, + const GattCharacteristic& characteristic) = 0; }; // https://developer.android.com/reference/android/bluetooth/BluetoothGattServer // // Representation of a BLE GATT server. -class GATTServer { +class GattServer { public: - virtual ~GATTServer() {} + virtual ~GattServer() {} // Creates a characteristic and adds it to the GATT server under the given - // characteristic and service UUIDs. Returns a null Ptr upon error. + // characteristic and service UUIDs. Returns no value upon error. // // Characteristics of the same service UUID should be put under one // service rather than many services with the same UUID. @@ -215,12 +208,11 @@ class GATTServer { // 0x2902 and a WRITE permission. This allows remote clients to write to this // descriptor and subscribe for characteristic changes. For more information // about this descriptor, please go to: - // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml - virtual Ptr createCharacteristic( - const std::string& service_uuid, - const std::string& characteristic_uuid, - const std::set& permissions, - const std::set& properties) = 0; + // https://www.bluetooth.com/specifications/Gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.Gatt.client_characteristic_configuration.xml + virtual absl::optional CreateCharacteristic( + absl::string_view service_uuid, absl::string_view characteristic_uuid, + const std::set& permissions, + const std::set& properties) = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#setValue(byte[]) // @@ -228,67 +220,66 @@ class GATTServer { // was successful. // Takes ownership of (and is responsible for destroying) the passed-in // 'value'. - virtual bool updateCharacteristic(Ptr characteristic, - ConstPtr value) = 0; + virtual bool UpdateCharacteristic(const GattCharacteristic& characteristic, + const ByteArray& value) = 0; // Stops a GATT server. - virtual void stop() = 0; + virtual void Stop() = 0; }; // A BLE socket representation. -class BLESocketV0 { +class BleSocket { public: - virtual ~BLESocketV0() {} + virtual ~BleSocket() {} // Returns the remote BLE peripheral tied to this socket. - virtual Ptr getRemotePeripheral() = 0; + virtual BlePeripheral& GetRemotePeripheral() = 0; // Writes a message on the socket and blocks until finished. Returns - // Exception::IO upon error, and Exception::NONE otherwise. - virtual Exception::Value write(ConstPtr message) = 0; + // Exception::kIo upon error, and Exception::kSuccess otherwise. + virtual Exception Write(const ByteArray& message) = 0; - // Closes the socket and blocks until finished. Returns Exception::IO upon - // error, and Exception::NONE otherwise. - virtual Exception::Value close() = 0; + // Closes the socket and blocks until finished. Returns Exception::kIo upon + // error, and Exception::kSuccess otherwise. + virtual Exception Close() = 0; }; -// Callback for asynchronous events on a BLESocketV0 object. -class BLESocketLifecycleCallback { +// Callback for asynchronous events on a BleSocket object. +class BleSocketLifeCycleCallback { public: - virtual ~BLESocketLifecycleCallback() {} + virtual ~BleSocketLifeCycleCallback() {} // Called when a message arrives on a socket. - virtual void onMessageReceived(Ptr socket, - ConstPtr message) = 0; + virtual void OnMessageReceived(BleSocket* socket, + const ByteArray& message) = 0; // Called when a socket gets disconnected. - virtual void onDisconnected(Ptr socket) = 0; + virtual void OnDisconnected(BleSocket* socket) = 0; }; -// Callback for asynchronous events on the server side of a BLESocketV0 object. -class ServerBLESocketLifecycleCallback : public BLESocketLifecycleCallback { +// Callback for asynchronous events on the server side of a BleSocket object. +class ServerBleSocketLifeCycleCallback : public BleSocketLifeCycleCallback { public: - ~ServerBLESocketLifecycleCallback() override {} + ~ServerBleSocketLifeCycleCallback() override {} // Called when a new incoming socket has been established. - virtual void onSocketEstablished(Ptr socket) = 0; + virtual void OnSocketEstablished(BleSocket* socket) = 0; }; // The main BLE medium used inside of Nearby. This serves as the entry point for // all BLE and GATT related operations. -class BLEMediumV2 { +class BleMedium { public: - virtual ~BLEMediumV2() {} + using Mtu = uint32_t; - typedef std::uint32_t MTU; + virtual ~BleMedium() {} // Coarse representation of power settings throughout all BLE operations. - struct PowerMode { - enum Value { - UNKNOWN = 0, - LOW = 1, - HIGH = 2, - }; + enum class PowerMode { + kUnknown = 0, + kLow = 1, + kHigh = 2, + kLast, }; // https://developer.android.com/reference/android/bluetooth/le/BluetoothLeAdvertiser.html#startAdvertising(android.bluetooth.le.AdvertiseSettings,%20android.bluetooth.le.AdvertiseData,%20android.bluetooth.le.AdvertiseData,%20android.bluetooth.le.AdvertiseCallback) @@ -302,15 +293,14 @@ class BLEMediumV2 { // HIGH: // - Advertising interval = ~100ms // - TX power = high - virtual bool startAdvertising( - ConstPtr advertisement_data, - ConstPtr scan_response, - PowerMode::Value power_mode) = 0; + virtual bool StartAdvertising(const BleAdvertisementData& advertisement_data, + const BleAdvertisementData& scan_response, + PowerMode power_mode) = 0; // https://developer.android.com/reference/android/bluetooth/le/BluetoothLeAdvertiser.html#stopAdvertising(android.bluetooth.le.AdvertiseCallback) // // Stops advertising. - virtual void stopAdvertising() = 0; + virtual void StopAdvertising() = 0; // https://developer.android.com/reference/android/bluetooth/le/ScanCallback // @@ -329,11 +319,11 @@ class BLEMediumV2 { // Every discovery of an advertisement should be reported, even if the // advertisement was discovered before. // - // Ownership of the BLEAdvertisementData transfers to the caller at this + // Ownership of the BleAdvertisementData transfers to the caller at this // point. - virtual void onAdvertisementFound( - Ptr peripheral, - ConstPtr advertisement_data) = 0; + virtual void OnAdvertisementFound( + BlePeripheral* peripheral, + const BleAdvertisementData& advertisement_data) = 0; }; // https://developer.android.com/reference/android/bluetooth/le/BluetoothLeScanner.html#startScan(java.util.List%3Candroid.bluetooth.le.ScanFilter%3E,%20android.bluetooth.le.ScanSettings,%20android.bluetooth.le.ScanCallback) @@ -347,35 +337,34 @@ class BLEMediumV2 { // HIGH: // - Scan window = ~4096ms // - Scan interval = ~4096ms - virtual bool startScanning(const std::set& service_uuids, - PowerMode::Value power_mode, - Ptr scan_callback) = 0; + virtual bool StartScanning(const std::set& service_uuids, + PowerMode power_mode, + const ScanCallback& scan_callback) = 0; // https://developer.android.com/reference/android/bluetooth/le/BluetoothLeScanner.html#stopScan(android.bluetooth.le.ScanCallback) // // Stops scanning. - virtual void stopScanning() = 0; + virtual void StopScanning() = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothManager#openGattServer(android.content.Context,%20android.bluetooth.BluetoothGattServerCallback) // - // Starts a GATT server. Returns a null Ptr upon error. - virtual Ptr startGATTServer( - Ptr - connection_lifecycle_callback) = 0; + // Starts a GATT server. Returns a nullptr upon error. + virtual std::unique_ptr StartGattServer( + const ServerGattConnectionLifeCycleCallback& callback) = 0; // Starts listening for incoming BLE sockets and returns false upon error. - virtual bool startListeningForIncomingBLESockets( - Ptr socket_lifecycle_callback) = 0; + virtual bool StartListeningForIncomingBleSockets( + const ServerBleSocketLifeCycleCallback& callback) = 0; // Stops listening for incoming BLE sockets. - virtual void stopListeningForIncomingBLESockets() = 0; + virtual void StopListeningForIncomingBleSockets() = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#connectGatt(android.content.Context,%20boolean,%20android.bluetooth.BluetoothGattCallback) // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#requestConnectionPriority(int) // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#requestMtu(int) // // Connects to a GATT server and negotiates the specified connection - // parameters. Returns a null Ptr upon error. + // parameters. Returns nullptr upon error. // // Both connection interval and MTU can be negotiated on a best-effort basis. // @@ -384,20 +373,19 @@ class BLEMediumV2 { // - Connection interval = ~11.25ms - 15ms // HIGH: // - Connection interval = ~100ms - 125ms - virtual Ptr connectToGATTServer( - Ptr peripheral, - MTU mtu, - PowerMode::Value power_mode, - Ptr - connection_lifecycle_callback) = 0; + virtual std::unique_ptr ConnectToGattServer( + BlePeripheral* peripheral, Mtu mtu, PowerMode power_mode, + const ClientGattConnectionLifeCycleCallback& callback) = 0; - // Establishes a BLE socket to the specified remote peripheral. Returns a null - // Ptr on error. - virtual Ptr establishBLESocket( - Ptr ble_peripheral, - Ptr socket_lifecycle_callback) = 0; + // Establishes a BLE socket to the specified remote peripheral. Returns + // nullptr on error. + virtual std::unique_ptr EstablishBleSocket( + BlePeripheral* peripheral, + const BleSocketLifeCycleCallback& callback) = 0; }; +} // namespace ble_v2 +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform/api/bluetooth_adapter.h b/cpp/platform/api/bluetooth_adapter.h index 04223492..ddcce2a7 100644 --- a/cpp/platform/api/bluetooth_adapter.h +++ b/cpp/platform/api/bluetooth_adapter.h @@ -1,57 +1,60 @@ #ifndef PLATFORM_API_BLUETOOTH_ADAPTER_H_ #define PLATFORM_API_BLUETOOTH_ADAPTER_H_ -#include "platform/port/string.h" -#include "platform/ptr.h" +#include + +#include "absl/strings/string_view.h" namespace location { namespace nearby { +namespace api { // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html class BluetoothAdapter { public: - virtual ~BluetoothAdapter() {} + virtual ~BluetoothAdapter() = default; // Eligible statuses of the BluetoothAdapter. - struct Status { - enum Value { - DISABLED, - ENABLED, - }; + enum class Status { + kDisabled, + kEnabled, }; // Synchronously sets the status of the BluetoothAdapter to 'status', and // returns true if the operation was a success. - virtual bool setStatus(Status::Value status) = 0; + virtual bool SetStatus(Status status) = 0; // Returns true if the BluetoothAdapter's current status is - // Status::Value::ENABLED. - virtual bool isEnabled() = 0; + // Status::Value::kEnabled. + virtual bool IsEnabled() const = 0; // Scan modes of a BluetoothAdapter, as described at // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getScanMode(). - struct ScanMode { - enum Value { - UNKNOWN, - CONNECTABLE_DISCOVERABLE, - }; + enum class ScanMode { + kUnknown, + kNone, + kConnectable, + kConnectableDiscoverable, }; // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getScanMode() // - // Returns ScanMode::UNKNOWN on error. - virtual ScanMode::Value getScanMode() = 0; + // Returns ScanMode::kUnknown on error. + virtual ScanMode GetScanMode() const = 0; // Synchronously sets the scan mode of the adapter, and returns true if the // operation was a success. - virtual bool setScanMode(ScanMode::Value scan_mode) = 0; + virtual bool SetScanMode(ScanMode scan_mode) = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getName() - // - // Returns a null Ptr on error. - virtual Ptr getName() = 0; + // Returns an empty string on error + virtual std::string GetName() const = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#setName(java.lang.String) - virtual bool setName(const std::string& name) = 0; + virtual bool SetName(absl::string_view name) = 0; + + // Returns BT MAC address assigned to this adapter. + virtual std::string GetMacAddress() const = 0; }; +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform/api/bluetooth_classic.h b/cpp/platform/api/bluetooth_classic.h index 154c7f0f..502c49fc 100644 --- a/cpp/platform/api/bluetooth_classic.h +++ b/cpp/platform/api/bluetooth_classic.h @@ -1,107 +1,112 @@ #ifndef PLATFORM_API_BLUETOOTH_CLASSIC_H_ #define PLATFORM_API_BLUETOOTH_CLASSIC_H_ -#include "platform/api/input_stream.h" -#include "platform/api/output_stream.h" -#include "platform/byte_array.h" -#include "platform/exception.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include +#include + +#include "platform/base/byte_array.h" +#include "platform/base/exception.h" +#include "platform/base/input_stream.h" +#include "platform/base/listeners.h" +#include "platform/base/output_stream.h" namespace location { namespace nearby { +namespace api { // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html. class BluetoothDevice { public: - virtual ~BluetoothDevice() {} + virtual ~BluetoothDevice() = default; // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName() - virtual std::string getName() = 0; + virtual std::string GetName() const = 0; + + // Returns BT MAC address assigned to this device. + virtual std::string GetMacAddress() const = 0; }; // https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html. class BluetoothSocket { public: - virtual ~BluetoothSocket() {} + virtual ~BluetoothSocket() = default; - // Returns the InputStream of the BluetoothSocket, or a null Ptr - // on error. - // - // The returned Ptr is not owned by the caller, and can be invalidated once - // the BluetoothSocket object is destroyed. - virtual Ptr getInputStream() = 0; + // NOTE: + // It is an undefined behavior if GetInputStream() or GetOutputStream() is + // called for a not-connected BluetoothSocket, i.e. any object that is not + // returned by BluetoothClassicMedium::ConnectToService() for client side or + // BluetoothServerSocket::Accept() for server side of connection. - // Returns the OutputStream of the BluetoothSocket, or a null - // Ptr on error. - // - // The returned Ptr is not owned by the caller, and can be invalidated once - // the BluetoothSocket object is destroyed. - virtual Ptr getOutputStream() = 0; + // Returns the InputStream of this connected BluetoothSocket. + virtual InputStream& GetInputStream() = 0; - // https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#close() - // - // Returns Exception::IO on error, Exception::NONE otherwise. - virtual Exception::Value close() = 0; + // Returns the OutputStream of this connected BluetoothSocket. + virtual OutputStream& GetOutputStream() = 0; + + // Closes both input and output streams, marks Socket as closed. + // After this call object should be treated as not connected. + // Returns Exception::kIo on error, Exception::kSuccess otherwise. + virtual Exception Close() = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#getRemoteDevice() - // - // The returned Ptr is not owned by the caller, and can be invalidated once - // the BluetoothSocket object is destroyed. - virtual Ptr getRemoteDevice() = 0; + // Returns valid BluetoothDevice pointer if there is a connection, and + // nullptr otherwise. + virtual BluetoothDevice* GetRemoteDevice() = 0; }; // https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html. class BluetoothServerSocket { public: - virtual ~BluetoothServerSocket() {} + virtual ~BluetoothServerSocket() = default; // https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#accept() // - // The returned Ptr will be owned (and destroyed) by the caller. Returns - // Exception::IO on error. - virtual ExceptionOr> accept() = 0; + // Blocks until either: + // - at least one incoming connection request is available, or + // - ServerSocket is closed. + // On success, returns connected socket, ready to exchange data. + // Returns nullptr on error. + // Once error is reported, it is permanent, and ServerSocket has to be closed. + virtual std::unique_ptr Accept() = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#close() // - // Returns Exception::IO on error, Exception::NONE otherwise. - virtual Exception::Value close() = 0; + // Returns Exception::kIo on error, Exception::kSuccess otherwise. + virtual Exception Close() = 0; }; // Container of operations that can be performed over the Bluetooth Classic // medium. class BluetoothClassicMedium { public: - virtual ~BluetoothClassicMedium() {} + virtual ~BluetoothClassicMedium() = default; - class DiscoveryCallback { - public: - virtual ~DiscoveryCallback() {} - - // The Ptrs provided in these callback methods will be owned (and - // destroyed) by the recipient of the callback methods (i.e. the creator of - // the concrete DiscoveryCallback object). - virtual void onDeviceDiscovered(Ptr device) = 0; - virtual void onDeviceNameChanged(Ptr device) = 0; - virtual void onDeviceLost(Ptr device) = 0; + struct DiscoveryCallback { + // BluetoothDevice is a proxy object created as a result of BT discovery. + // Its lifetime spans between calls to device_discovered_cb and + // device_lost_cb. + // It is safe to use BluetoothDevice in device_discovered_cb() callback + // and at any time afterwards, until device_lost_cb() is called. + // It is not safe to use BluetoothDevice after returning from + // device_lost_cb() callback. + std::function device_discovered_cb = + DefaultCallback(); + std::function device_name_changed_cb = + DefaultCallback(); + std::function device_lost_cb = + DefaultCallback(); }; // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery() // // Returns true once the process of discovery has been initiated. - // - // Does not take ownership of the passed-in discovery_callback -- destroying - // that is up to the caller. - virtual bool startDiscovery(Ptr discovery_callback) = 0; + virtual bool StartDiscovery(DiscoveryCallback discovery_callback) = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#cancelDiscovery() // // Returns true once discovery is well and truly stopped; after this returns, // there must be no more invocations of the DiscoveryCallback passed in to - // startDiscovery(). - // - // Does not need to bother with destroying the DiscoveryCallback passed in to - // startDiscovery() -- that's the job of the caller. - virtual bool stopDiscovery() = 0; + // StartDiscovery(). + virtual bool StopDiscovery() = 0; // A combination of // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createInsecureRfcommSocketToServiceRecord @@ -114,11 +119,10 @@ class BluetoothClassicMedium { // (https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions_3_and_5_(namespace_name-based)) // UUID. // - // The returned Ptr will be owned (and destroyed) by the caller. Returns - // Exception::IO on error. - virtual ExceptionOr> connectToService( - Ptr remote_device, - const std::string& service_uuid) = 0; + // On success, returns a new BluetoothSocket. + // On error, returns nullptr. + virtual std::unique_ptr ConnectToService( + BluetoothDevice& remote_device, const std::string& service_uuid) = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#listenUsingInsecureRfcommWithServiceRecord // @@ -128,13 +132,14 @@ class BluetoothClassicMedium { // (https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions_3_and_5_(namespace_name-based)) // UUID. // - // The returned Ptr will be owned (and destroyed) by the caller. Returns - // Exception::IO on error. - virtual ExceptionOr> listenForService( - const std::string& service_name, - const std::string& service_uuid) = 0; + // Returns nullptr error. + virtual std::unique_ptr ListenForService( + const std::string& service_name, const std::string& service_uuid) = 0; + + virtual BluetoothDevice* GetRemoteDevice(const std::string& mac_address) = 0; }; +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform_v2/api/cancelable.h b/cpp/platform/api/cancelable.h similarity index 73% rename from cpp/platform_v2/api/cancelable.h rename to cpp/platform/api/cancelable.h index 56eb5699..0acda9a7 100644 --- a/cpp/platform_v2/api/cancelable.h +++ b/cpp/platform/api/cancelable.h @@ -1,5 +1,5 @@ -#ifndef PLATFORM_V2_API_CANCELABLE_H_ -#define PLATFORM_V2_API_CANCELABLE_H_ +#ifndef PLATFORM_API_CANCELABLE_H_ +#define PLATFORM_API_CANCELABLE_H_ namespace location { namespace nearby { @@ -18,4 +18,4 @@ class Cancelable { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_API_CANCELABLE_H_ +#endif // PLATFORM_API_CANCELABLE_H_ diff --git a/cpp/platform/api/condition_variable.h b/cpp/platform/api/condition_variable.h index b40aa7f5..bbbd2d71 100644 --- a/cpp/platform/api/condition_variable.h +++ b/cpp/platform/api/condition_variable.h @@ -1,10 +1,12 @@ #ifndef PLATFORM_API_CONDITION_VARIABLE_H_ #define PLATFORM_API_CONDITION_VARIABLE_H_ -#include "platform/exception.h" +#include "platform/base/exception.h" +#include "absl/time/clock.h" namespace location { namespace nearby { +namespace api { // The ConditionVariable class is a synchronization primitive that can be used // to block a thread, or multiple threads at the same time, until another thread @@ -14,12 +16,21 @@ class ConditionVariable { public: virtual ~ConditionVariable() {} - // https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#notify-- - virtual void notify() = 0; - // https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#wait-- - virtual Exception::Value wait() = 0; // throws Exception::INTERRUPTED + // Notifies all the waiters that condition state has changed. + virtual void Notify() = 0; + + // Waits indefinitely for Notify to be called. + // May return prematurely in case of interrupt, if supported by platform. + // Returns kSuccess, or kInterrupted on interrupt. + virtual Exception Wait() = 0; + + // Waits while timeout has not expired for Notify to be called. + // May return prematurely in case of interrupt, if supported by platform. + // Returns kSuccess, or kInterrupted on interrupt. + virtual Exception Wait(absl::Duration timeout) = 0; }; +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform/api/count_down_latch.h b/cpp/platform/api/count_down_latch.h index d5b99f95..ed6b0f57 100644 --- a/cpp/platform/api/count_down_latch.h +++ b/cpp/platform/api/count_down_latch.h @@ -3,10 +3,12 @@ #include -#include "platform/exception.h" +#include "platform/base/exception.h" +#include "absl/time/time.h" namespace location { namespace nearby { +namespace api { // A synchronization aid that allows one or more threads to wait until a set of // operations being performed in other threads completes. @@ -14,14 +16,15 @@ namespace nearby { // https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CountDownLatch.html class CountDownLatch { public: - virtual ~CountDownLatch() {} + virtual ~CountDownLatch() = default; - virtual Exception::Value await() = 0; // throws Exception::INTERRUPTED - virtual ExceptionOr await( - std::int32_t timeout_millis) = 0; // throws Exception::INTERRUPTED - virtual void countDown() = 0; + virtual Exception Await() = 0; // throws Exception::kInterrupted + virtual ExceptionOr Await( + absl::Duration timeout) = 0; // throws Exception::kInterrupted + virtual void CountDown() = 0; }; +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform_v2/api/crypto.h b/cpp/platform/api/crypto.h similarity index 74% rename from cpp/platform_v2/api/crypto.h rename to cpp/platform/api/crypto.h index c43279b3..5ef8c269 100644 --- a/cpp/platform_v2/api/crypto.h +++ b/cpp/platform/api/crypto.h @@ -1,7 +1,7 @@ -#ifndef PLATFORM_V2_API_CRYPTO_H_ -#define PLATFORM_V2_API_CRYPTO_H_ +#ifndef PLATFORM_API_CRYPTO_H_ +#define PLATFORM_API_CRYPTO_H_ -#include "platform_v2/base/byte_array.h" +#include "platform/base/byte_array.h" #include "absl/strings/string_view.h" namespace location { @@ -21,4 +21,4 @@ class Crypto { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_API_CRYPTO_H_ +#endif // PLATFORM_API_CRYPTO_H_ diff --git a/cpp/platform/api/executor.h b/cpp/platform/api/executor.h index 2755af36..b616688a 100644 --- a/cpp/platform/api/executor.h +++ b/cpp/platform/api/executor.h @@ -1,25 +1,31 @@ #ifndef PLATFORM_API_EXECUTOR_H_ #define PLATFORM_API_EXECUTOR_H_ -#include "platform/ptr.h" -#include "platform/runnable.h" +#include "platform/base/runnable.h" namespace location { namespace nearby { +namespace api { + +int GetCurrentTid(); // This abstract class is the superclass of all classes representing an // Executor. class Executor { public: - virtual ~Executor() {} + // Before returning from destructor, executor must wait for all pending + // jobs to finish. + virtual ~Executor() = default; + // https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html#execute-java.lang.Runnable- + virtual void Execute(Runnable&& runnable) = 0; // https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html#shutdown-- - virtual void shutdown() = 0; + virtual void Shutdown() = 0; - // https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html#execute-java.lang.Runnable- - virtual void execute(Ptr runnable) = 0; + virtual int GetTid(int index) const = 0; }; +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform/api/future.h b/cpp/platform/api/future.h index 166a4ed9..2469ae3c 100644 --- a/cpp/platform/api/future.h +++ b/cpp/platform/api/future.h @@ -1,12 +1,12 @@ #ifndef PLATFORM_API_FUTURE_H_ #define PLATFORM_API_FUTURE_H_ -#include - -#include "platform/exception.h" +#include "platform/base/exception.h" +#include "absl/time/clock.h" namespace location { namespace nearby { +namespace api { // A Future represents the result of an asynchronous computation. // @@ -14,17 +14,18 @@ namespace nearby { template class Future { public: - virtual ~Future() {} + virtual ~Future() = default; - virtual ExceptionOr - get() = 0; // throws Exception::INTERRUPTED, Exception::EXECUTION + // throws Exception::kInterrupted, Exception::kExecution + virtual ExceptionOr Get() = 0; - // throws Exception::INTERRUPTED, Exception::EXECUTION - // throws Exception::TIMEOUT if |timeout_ms| is exceeded while waiting for + // throws Exception::kInterrupted, Exception::kExecution + // throws Exception::kTimeout if timeout is exceeded while waiting for // result. - virtual ExceptionOr get(std::int64_t timeout_ms) = 0; + virtual ExceptionOr Get(absl::Duration timeout) = 0; }; +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform/api/hash_utils.h b/cpp/platform/api/hash_utils.h deleted file mode 100644 index 12083380..00000000 --- a/cpp/platform/api/hash_utils.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef PLATFORM_API_HASH_UTILS_H_ -#define PLATFORM_API_HASH_UTILS_H_ - -#include "platform/byte_array.h" -#include "platform/port/string.h" -#include "platform/ptr.h" - -namespace location { -namespace nearby { - -// A provider of standard hashing algorithms. -class HashUtils { - public: - virtual ~HashUtils() {} - - virtual ConstPtr md5(const std::string& input) = 0; - virtual ConstPtr sha256(const std::string& input) = 0; -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_API_HASH_UTILS_H_ diff --git a/cpp/platform/api/input_file.h b/cpp/platform/api/input_file.h index ed2c782a..eacb7a23 100644 --- a/cpp/platform/api/input_file.h +++ b/cpp/platform/api/input_file.h @@ -1,29 +1,25 @@ #ifndef PLATFORM_API_INPUT_FILE_H_ #define PLATFORM_API_INPUT_FILE_H_ -#include "platform/byte_array.h" -#include "platform/exception.h" -#include "platform/ptr.h" +#include + +#include "platform/base/byte_array.h" +#include "platform/base/exception.h" +#include "platform/base/input_stream.h" namespace location { namespace nearby { +namespace api { // An InputFile represents a readable file on the system. -class InputFile { +class InputFile : public InputStream { public: - virtual ~InputFile() {} - - // The returned ConstPtr will be owned (and destroyed) by the caller. - // When we have exhausted reading the file and no bytes remain, read will - // always return an empty ConstPtr for which isNull() is true. - virtual ExceptionOr> read( - std::int64_t size) = 0; // throws Exception::IO when the file cannot be - // opened or read. - virtual std::string getFilePath() const = 0; - virtual std::int64_t getTotalSize() const = 0; - virtual void close() = 0; + ~InputFile() override = default; + virtual std::string GetFilePath() const = 0; + virtual std::int64_t GetTotalSize() const = 0; }; +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform/api/input_stream.h b/cpp/platform/api/input_stream.h deleted file mode 100644 index 02eb6502..00000000 --- a/cpp/platform/api/input_stream.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef PLATFORM_API_INPUT_STREAM_H_ -#define PLATFORM_API_INPUT_STREAM_H_ - -#include - -#include "platform/byte_array.h" -#include "platform/exception.h" -#include "platform/ptr.h" - -namespace location { -namespace nearby { - -// An InputStream represents an input stream of bytes. -// -// https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html -class InputStream { - public: - virtual ~InputStream() {} - - // The returned ConstPtr will be owned (and destroyed) by the caller. - virtual ExceptionOr> read() = 0; // throws Exception::IO - // The returned ConstPtr will be owned (and destroyed) by the caller. - virtual ExceptionOr> read( - std::int64_t size) = 0; // throws Exception::IO - virtual Exception::Value close() = 0; // throws Exception::IO -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_API_INPUT_STREAM_H_ diff --git a/cpp/platform/api/listenable_future.h b/cpp/platform/api/listenable_future.h index 3cd306e7..d013842b 100644 --- a/cpp/platform/api/listenable_future.h +++ b/cpp/platform/api/listenable_future.h @@ -1,14 +1,17 @@ #ifndef PLATFORM_API_LISTENABLE_FUTURE_H_ #define PLATFORM_API_LISTENABLE_FUTURE_H_ +#include +#include + #include "platform/api/executor.h" #include "platform/api/future.h" -#include "platform/exception.h" -#include "platform/ptr.h" -#include "platform/runnable.h" +#include "platform/base/exception.h" +#include "platform/base/runnable.h" namespace location { namespace nearby { +namespace api { // A Future that accepts completion listeners. // @@ -16,12 +19,13 @@ namespace nearby { template class ListenableFuture : public Future { public: - ~ListenableFuture() override {} + ~ListenableFuture() override = default; - // Executor is shared among multiple runnables. It is not owned by any future. - virtual void addListener(Ptr runnable, Executor* executor) = 0; + virtual void AddListener(Runnable runnable, + Executor* executor) = 0; }; +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform/api/lock.h b/cpp/platform/api/lock.h deleted file mode 100644 index 1c93aa8c..00000000 --- a/cpp/platform/api/lock.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef PLATFORM_API_LOCK_H_ -#define PLATFORM_API_LOCK_H_ - -namespace location { -namespace nearby { - -// A lock is a tool for controlling access to a shared resource by multiple -// threads. -// -// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html -class Lock { - public: - virtual ~Lock() {} - - virtual void lock() = 0; - virtual void unlock() = 0; -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_API_LOCK_H_ diff --git a/cpp/platform_v2/api/log_message.h b/cpp/platform/api/log_message.h similarity index 88% rename from cpp/platform_v2/api/log_message.h rename to cpp/platform/api/log_message.h index f2e25e48..596b6270 100644 --- a/cpp/platform_v2/api/log_message.h +++ b/cpp/platform/api/log_message.h @@ -1,5 +1,5 @@ -#ifndef PLATFORM_V2_API_LOG_MESSAGE_H_ -#define PLATFORM_V2_API_LOG_MESSAGE_H_ +#ifndef PLATFORM_API_LOG_MESSAGE_H_ +#define PLATFORM_API_LOG_MESSAGE_H_ #include @@ -38,4 +38,4 @@ class LogMessage { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_API_LOG_MESSAGE_H_ +#endif // PLATFORM_API_LOG_MESSAGE_H_ diff --git a/cpp/platform/api/multi_thread_executor.h b/cpp/platform/api/multi_thread_executor.h deleted file mode 100644 index f9aa8b9c..00000000 --- a/cpp/platform/api/multi_thread_executor.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef PLATFORM_API_MULTI_THREAD_EXECUTOR_H_ -#define PLATFORM_API_MULTI_THREAD_EXECUTOR_H_ - -#include "platform/api/submittable_executor.h" - -namespace location { -namespace nearby { - -// An Executor that reuses a fixed number of threads operating off a shared -// unbounded queue. -// -// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool-int- -class MultiThreadExecutor : public SubmittableExecutor { - public: - ~MultiThreadExecutor() override = default; -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_API_MULTI_THREAD_EXECUTOR_H_ diff --git a/cpp/platform_v2/api/mutex.h b/cpp/platform/api/mutex.h similarity index 91% rename from cpp/platform_v2/api/mutex.h rename to cpp/platform/api/mutex.h index b7ed29d6..d4afc1cb 100644 --- a/cpp/platform_v2/api/mutex.h +++ b/cpp/platform/api/mutex.h @@ -1,5 +1,5 @@ -#ifndef PLATFORM_V2_API_MUTEX_H_ -#define PLATFORM_V2_API_MUTEX_H_ +#ifndef PLATFORM_API_MUTEX_H_ +#define PLATFORM_API_MUTEX_H_ #include "absl/base/thread_annotations.h" @@ -38,4 +38,4 @@ class ABSL_LOCKABLE Mutex { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_API_MUTEX_H_ +#endif // PLATFORM_API_MUTEX_H_ diff --git a/cpp/platform/api/output_file.h b/cpp/platform/api/output_file.h index b600d539..f371fdfb 100644 --- a/cpp/platform/api/output_file.h +++ b/cpp/platform/api/output_file.h @@ -1,25 +1,21 @@ #ifndef PLATFORM_API_OUTPUT_FILE_H_ #define PLATFORM_API_OUTPUT_FILE_H_ -#include "platform/byte_array.h" -#include "platform/exception.h" -#include "platform/ptr.h" +#include "platform/base/byte_array.h" +#include "platform/base/exception.h" +#include "platform/base/output_stream.h" namespace location { namespace nearby { +namespace api { // An OutputFile represents a writable file on the system. -class OutputFile { +class OutputFile : public OutputStream { public: - virtual ~OutputFile() {} - - // Takes ownership of the passed-in ConstPtr, and ensures that it is destroyed - // even upon error (i.e. when the return value is not Exception::NONE). - virtual Exception::Value write( - ConstPtr data) = 0; // throws Exception::IO - virtual void close() = 0; + ~OutputFile() override = default; }; +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform/api/output_stream.h b/cpp/platform/api/output_stream.h deleted file mode 100644 index fd4d8ea3..00000000 --- a/cpp/platform/api/output_stream.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef PLATFORM_API_OUTPUT_STREAM_H_ -#define PLATFORM_API_OUTPUT_STREAM_H_ - -#include "platform/byte_array.h" -#include "platform/exception.h" -#include "platform/ptr.h" - -namespace location { -namespace nearby { - -// An OutputStream represents an output stream of bytes. -// -// https://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html -class OutputStream { - public: - virtual ~OutputStream() {} - - // Takes ownership of the passed-in ConstPtr, and ensures that it is destroyed - // even upon error (i.e. when the return value is not Exception::NONE). - virtual Exception::Value write( - ConstPtr data) = 0; // throws Exception::IO - virtual Exception::Value flush() = 0; // throws Exception::IO - virtual Exception::Value close() = 0; // throws Exception::IO -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_API_OUTPUT_STREAM_H_ diff --git a/cpp/platform/api/platform.h b/cpp/platform/api/platform.h index 080b5ce0..bf7bbd3c 100644 --- a/cpp/platform/api/platform.h +++ b/cpp/platform/api/platform.h @@ -2,108 +2,95 @@ #define PLATFORM_API_PLATFORM_H_ #include +#include +#include #include "platform/api/atomic_boolean.h" -#include "platform/api/atomic_reference_def.h" +#include "platform/api/atomic_reference.h" #include "platform/api/ble.h" #include "platform/api/ble_v2.h" #include "platform/api/bluetooth_adapter.h" #include "platform/api/bluetooth_classic.h" #include "platform/api/condition_variable.h" #include "platform/api/count_down_latch.h" -#include "platform/api/hash_utils.h" +#include "platform/api/crypto.h" #include "platform/api/input_file.h" -#include "platform/api/lock.h" +#include "platform/api/log_message.h" +#include "platform/api/mutex.h" #include "platform/api/output_file.h" #include "platform/api/scheduled_executor.h" #include "platform/api/server_sync.h" -#include "platform/api/settable_future_def.h" -#include "platform/api/submittable_executor_def.h" +#include "platform/api/settable_future.h" +#include "platform/api/submittable_executor.h" #include "platform/api/system_clock.h" -#include "platform/api/thread_utils.h" #include "platform/api/webrtc.h" #include "platform/api/wifi.h" #include "platform/api/wifi_lan.h" - -// Project-specific basic types, that are not part of API. -// TODO(apolyudov): replace with c++ standard types. -#include "platform/port/string.h" -#include "platform/ptr.h" -#include "absl/types/any.h" +#include "platform/base/payload_id.h" +#include "absl/strings/string_view.h" namespace location { namespace nearby { -namespace platform { +namespace api { // API rework notes: // https://docs.google.com/spreadsheets/d/1erZNkX7pX8s5jWTHdxgjntxTMor3BGiY2H_fC_ldtoQ/edit#gid=381357998 class ImplementationPlatform { public: - // Class Templates in platform code. - // - // Platform interface does not support templates directly. - // This is a design decision. The purpose is to have type isolation - // between platform library (or simply platform) and core library. - // Another goal is to make a platform implementation a black box, - // which does not leak implementation details in any form, be that types, - // methods, or variables. - // - // Core library code does provide platform-specific class templates - // on top of (a non-templated) platform support. - // - // For every common library template that needs platform support, - // platform must provide an absl::any specialization of class template: - template - static Ptr> createAtomicReference(T initial_value = T{}); - template - static Ptr> createSettableFuture(); + // General platform support: + // - atomic variables (boolean, and any other copyable type) + // - synchronization primitives: + // - mutex (regular, and recursive) + // - condition variable (must work with regular mutex only) + // - Future : to synchronize on Callable scheduled to execute. + // - CountDownLatch : to ensure at least N threads are waiting. + // - file I/O + // - Logging - // AtomicReference - static Ptr> createAtomicReferenceAny( - absl::any initial_value); + // Atomics: + // ======= - // SettableFuture - static Ptr> createSettableFutureAny(); + // Atomic boolean: special case. Uses native platform atomics. + // Does not use locking. + // Does not use dynamic memory allocations in operations. + static std::unique_ptr CreateAtomicBoolean(bool initial_value); - // Non-template methods: general platform support. - static Ptr createAtomicBoolean(bool initial_value); - static Ptr createCountDownLatch(std::int32_t count); - static Ptr createLock(); - static Ptr createConditionVariable(Ptr lock); - static Ptr createHashUtils(); - static Ptr createThreadUtils(); - static Ptr createSystemClock(); - static Ptr createInputFile(std::int64_t payload_id, - std::int64_t total_size); - static Ptr createOutputFile(std::int64_t payload_id); + // Supports enums and integers up to 32-bit. + // Does not use locking, if platform supports 32-bit atimics natively. + // Does not use dynamic memory allocations in operations. + static std::unique_ptr CreateAtomicUint32(std::uint32_t value); + + static std::unique_ptr CreateCountDownLatch( + std::int32_t count); + static std::unique_ptr CreateMutex(Mutex::Mode mode); + static std::unique_ptr CreateConditionVariable( + Mutex* mutex); + static std::unique_ptr CreateInputFile(PayloadId payload_id, + std::int64_t total_size); + static std::unique_ptr CreateOutputFile(PayloadId payload_id); + static std::unique_ptr CreateLogMessage( + const char* file, int line, LogMessage::Severity severity); // Java-like Executors - // Type aliases used to API 1.0 compatibility. - // They will be retired soon. - // TODO(apolyudov): cleanup. - using SingleThreadExecutorType = SubmittableExecutor; - using MultiThreadExecutorType = SubmittableExecutor; - using ScheduledExecutorType = ScheduledExecutor; - - static Ptr createSingleThreadExecutor(); - static Ptr createMultiThreadExecutor( + static std::unique_ptr CreateSingleThreadExecutor(); + static std::unique_ptr CreateMultiThreadExecutor( std::int32_t max_concurrency); - static Ptr createScheduledExecutor(); + static std::unique_ptr CreateScheduledExecutor(); // Protocol implementations, domain-specific support - static Ptr createBluetoothAdapter(); - static Ptr createWifiMedium(); - static Ptr createBluetoothClassicMedium(); - static Ptr createBLEMedium(); - static Ptr createBLEMediumV2(); - static Ptr createServerSyncMedium(); - static Ptr createWifiLanMedium(); - static Ptr createWebRtcSignalingMessenger( - const std::string& self_id); - static std::string getDeviceId(); + static std::unique_ptr CreateBluetoothAdapter(); + static std::unique_ptr CreateBluetoothClassicMedium( + BluetoothAdapter&); + static std::unique_ptr CreateBleMedium(BluetoothAdapter&); + static std::unique_ptr CreateBleV2Medium( + BluetoothAdapter&); + static std::unique_ptr CreateServerSyncMedium(); + static std::unique_ptr CreateWifiMedium(); + static std::unique_ptr CreateWifiLanMedium(); + static std::unique_ptr CreateWebRtcMedium(); }; -} // namespace platform +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform/api/scheduled_executor.h b/cpp/platform/api/scheduled_executor.h index f4877450..778d1e72 100644 --- a/cpp/platform/api/scheduled_executor.h +++ b/cpp/platform/api/scheduled_executor.h @@ -2,27 +2,34 @@ #define PLATFORM_API_SCHEDULED_EXECUTOR_H_ #include +#include +#include -#include "platform/api/submittable_executor_def.h" -#include "platform/cancelable.h" -#include "platform/ptr.h" -#include "platform/runnable.h" +#include "platform/api/cancelable.h" +#include "platform/api/executor.h" +#include "platform/base/runnable.h" +#include "absl/time/time.h" namespace location { namespace nearby { +namespace api { // An Executor that can schedule commands to run after a given delay, or to // execute periodically. // // https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledExecutorService.html -class ScheduledExecutor : public SubmittableExecutor { +class ScheduledExecutor : public Executor { public: ~ScheduledExecutor() override = default; - - virtual Ptr schedule(Ptr runnable, - std::int64_t delay_millis) = 0; + // Cancelable is kept both in the executor context, and in the caller context. + // We want Cancelable to live until both caller and executor are done with it. + // Exclusive ownership model does not work for this case; + // using std:shared_ptr<> instead if std::unique_ptr<>. + virtual std::shared_ptr Schedule(Runnable&& runnable, + absl::Duration duration) = 0; }; +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform/api/server_sync.h b/cpp/platform/api/server_sync.h index 1be12149..3421693c 100644 --- a/cpp/platform/api/server_sync.h +++ b/cpp/platform/api/server_sync.h @@ -3,61 +3,59 @@ #include -#include "platform/byte_array.h" -#include "platform/ptr.h" +#include "platform/base/byte_array.h" +#include "absl/strings/string_view.h" namespace location { namespace nearby { +namespace api { // Abstraction that represents a Nearby endpoint exchanging data through // ServerSync Medium. class ServerSyncDevice { public: - virtual ~ServerSyncDevice() {} + virtual ~ServerSyncDevice() = default; - virtual std::string getName() = 0; - - virtual std::string getGuid() = 0; - - virtual std::string getOwnGuid() = 0; + virtual std::string GetName() const = 0; + virtual std::string GetGuid() const = 0; + virtual std::string GetOwnGuid() const = 0; }; -// Container of operations that can be performed over the Server Sync medium. +// Container of operations that can be performed over the Chrome Sync medium. class ServerSyncMedium { public: - virtual ~ServerSyncMedium() {} + virtual ~ServerSyncMedium() = default; - // Takes ownership of (and is responsible for destroying) the passed-in - // 'endpoint_info'. - virtual bool startAdvertising(const std::string& service_id, - const std::string& endpoint_id, - ConstPtr endpoint_info) = 0; - virtual void stopAdvertising(const std::string& service_id) = 0; + virtual bool StartAdvertising(absl::string_view service_id, + absl::string_view endpoint_id, + const ByteArray& endpoint_info) = 0; + virtual void StopAdvertising(absl::string_view service_id) = 0; class DiscoveredDeviceCallback { public: - virtual ~DiscoveredDeviceCallback() {} + virtual ~DiscoveredDeviceCallback() = default; // Called on a new ServerSyncDevice discovery. - virtual void onDeviceDiscovered(Ptr device, - const std::string& service_id, - const std::string& endpoint_id, - ConstPtr endpoint_info) = 0; + virtual void OnDeviceDiscovered(ServerSyncDevice* device, + absl::string_view service_id, + absl::string_view endpoint_id, + const ByteArray& endpoint_info) = 0; // Called when ServerSyncDevice is no longer reachable. - virtual void onDeviceLost(Ptr device, - const std::string& service_id) = 0; + virtual void OnDeviceLost(ServerSyncDevice* device, + absl::string_view service_id) = 0; }; // Returns true once the Chrome Sync scan has been initiated. - virtual bool startDiscovery( - const std::string& service_id, - Ptr discovered_device_callback) = 0; + virtual bool StartDiscovery( + absl::string_view service_id, + const DiscoveredDeviceCallback& discovered_device_callback) = 0; // Returns true once Chrome Sync scan for service_id is well and truly // stopped; after this returns, there must be no more invocations of the // DiscoveredDeviceCallback passed in to startScanning() for service_id. - virtual void stopDiscovery(const std::string& service_id) = 0; + virtual void StopDiscovery(absl::string_view service_id) = 0; }; +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform/api/settable_future.h b/cpp/platform/api/settable_future.h index 4fd69616..31487256 100644 --- a/cpp/platform/api/settable_future.h +++ b/cpp/platform/api/settable_future.h @@ -1,65 +1,34 @@ #ifndef PLATFORM_API_SETTABLE_FUTURE_H_ #define PLATFORM_API_SETTABLE_FUTURE_H_ -#include "platform/api/platform.h" -#include "platform/api/settable_future_def.h" -#include "platform/exception.h" -#include "platform/ptr.h" -#include "platform/runnable.h" -#include "absl/types/any.h" +#include "platform/api/listenable_future.h" +#include "platform/base/exception.h" namespace location { namespace nearby { +namespace api { -// "Common" part of implementation. -// Placed here for textual compatibility to minimize scope of changes. -// Can be (and should be) moved to a separate file outside "api" folder. -// TODO(apolyudov): for API v2.0 -namespace platform { -namespace impl { - +// A SettableFuture is a type of Future whose result can be set. +// +// https://google.github.io/guava/releases/20.0/api/docs/com/google/common/util/concurrent/SettableFuture.html template -class SettableFutureImpl : public SettableFuture { +class SettableFuture : public ListenableFuture { public: - SettableFutureImpl() { - future_ = platform::ImplementationPlatform::createSettableFutureAny(); - } + ~SettableFuture() override = default; - ~SettableFutureImpl() override = default; + // Completes the future successfully. The value is returned to any waiters. + // Returns true, if value was set. + // Returns false, if Future is already in "done" state. + virtual bool Set(T value) = 0; - bool set(T value) override { return future_->set(absl::any(value)); } - - bool setException(Exception exception) override { - return future_->setException(exception); - } - - void addListener(Ptr runnable, Executor* executor) override { - future_->addListener(runnable, executor); - } - - ExceptionOr get() override { return CommonGet(future_->get()); } - ExceptionOr get(std::int64_t timeout_ms) override { - return CommonGet(future_->get(timeout_ms)); - } - - private: - ExceptionOr CommonGet(ExceptionOr ret_val) { - if (ret_val.exception() != Exception::kSuccess) { - return ExceptionOr{ret_val.exception()}; - } - return ExceptionOr{absl::any_cast(ret_val.result())}; - } - - Ptr> future_; + // Completes the future unsuccessfully. The exception value is returned to any + // waiters. + // Returns true, if exception was set. + // Returns false, if Future is already in "done" state. + virtual bool SetException(Exception exception) = 0; }; -} // namespace impl -template -Ptr> ImplementationPlatform::createSettableFuture() { - return Ptr>(new impl::SettableFutureImpl{}); -} - -} // namespace platform +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform/api/settable_future_def.h b/cpp/platform/api/settable_future_def.h deleted file mode 100644 index e1a27c20..00000000 --- a/cpp/platform/api/settable_future_def.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef PLATFORM_API_SETTABLE_FUTURE_DEF_H_ -#define PLATFORM_API_SETTABLE_FUTURE_DEF_H_ - -#include "platform/api/listenable_future.h" -#include "platform/exception.h" - -namespace location { -namespace nearby { - -// A SettableFuture is a type of Future whose result can be set. -// -// https://google.github.io/guava/releases/20.0/api/docs/com/google/common/util/concurrent/SettableFuture.html -// -// Platform must implentent non-template static member functions -// Ptr> CreateSettableFutureSizeT() -// Ptr>> CreateSettableFuturePtr() -// in the location::nearby::platform::ImplementationPlatform class. -template -class SettableFuture : public ListenableFuture { - public: - ~SettableFuture() override = default; - - virtual bool set(T value) = 0; - - virtual bool setException(Exception exception) = 0; -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_API_SETTABLE_FUTURE_DEF_H_ diff --git a/cpp/platform/api/single_thread_executor.h b/cpp/platform/api/single_thread_executor.h deleted file mode 100644 index 51dd02a2..00000000 --- a/cpp/platform/api/single_thread_executor.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef PLATFORM_API_SINGLE_THREAD_EXECUTOR_H_ -#define PLATFORM_API_SINGLE_THREAD_EXECUTOR_H_ - -#include "platform/api/submittable_executor.h" - -namespace location { -namespace nearby { - -// An Executor that uses a single worker thread operating off an unbounded -// queue. -// -// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newSingleThreadExecutor-- -class SingleThreadExecutor : public SubmittableExecutor { - public: - ~SingleThreadExecutor() override = default; -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_API_SINGLE_THREAD_EXECUTOR_H_ diff --git a/cpp/platform/api/socket.h b/cpp/platform/api/socket.h deleted file mode 100644 index e6e69775..00000000 --- a/cpp/platform/api/socket.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef PLATFORM_API_SOCKET_H_ -#define PLATFORM_API_SOCKET_H_ - -#include "platform/api/input_stream.h" -#include "platform/api/output_stream.h" -#include "platform/ptr.h" - -namespace location { -namespace nearby { - -// A socket is an endpoint for communication between two machines. -// -// https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html -class Socket { - public: - virtual ~Socket() {} - - virtual Ptr getInputStream() = 0; - virtual Ptr getOutputStream() = 0; - virtual void close() = 0; -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_API_SOCKET_H_ diff --git a/cpp/platform/api/submittable_executor.h b/cpp/platform/api/submittable_executor.h index b84ae602..da90aeed 100644 --- a/cpp/platform/api/submittable_executor.h +++ b/cpp/platform/api/submittable_executor.h @@ -2,40 +2,31 @@ #define PLATFORM_API_SUBMITTABLE_EXECUTOR_H_ #include +#include #include "platform/api/executor.h" #include "platform/api/future.h" -#include "platform/api/platform.h" -#include "platform/api/settable_future.h" -#include "platform/api/submittable_executor_def.h" -#include "platform/exception.h" +#include "platform/base/runnable.h" namespace location { namespace nearby { +namespace api { -// "Common" part of implementation. -// Placed here for textual compatibility to minimize scope of changes. -// Can be (and should be) moved to a separate file outside "api" folder. -// TODO(apolyudov): for API v2.0 -template -Ptr> SubmittableExecutor::submit(Ptr> callable) { - using Platform = platform::ImplementationPlatform; - Ptr> future{Platform::createSettableFuture()}; - bool submitted = DoSubmit([callable, future]() { - ExceptionOr result = callable->call(); - if (result.ok()) { - future->set(std::move(result.result())); - } else { - future->setException({result.exception()}); - } - }); - if (!submitted) { - // Raise Exception::kExecution if we are shutting down. - future->setException({Exception::kExecution}); - } - return future; -} +// Main interface to be used by platform as a base class for +// - MultiThreadExecutorWrapper +// - SingleThreadExecutorWrapper +// Platform must override bool submit(std::function) method. +class SubmittableExecutor : public Executor { + public: + ~SubmittableExecutor() override = default; + // Submit a callable (with no delay). + // Returns true, if callable was submitted, false otherwise. + // Callable is not submitted if shutdown is in progress. + virtual bool DoSubmit(Runnable&& wrapped_callable) = 0; +}; + +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform/api/submittable_executor_def.h b/cpp/platform/api/submittable_executor_def.h deleted file mode 100644 index 0f7cd99c..00000000 --- a/cpp/platform/api/submittable_executor_def.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef PLATFORM_API_SUBMITTABLE_EXECUTOR_DEF_H_ -#define PLATFORM_API_SUBMITTABLE_EXECUTOR_DEF_H_ - -#include - -#include "platform/api/executor.h" -#include "platform/api/future.h" -#include "platform/callable.h" -#include "platform/ptr.h" - -namespace location { -namespace nearby { - -// Main interface to be used by platform as a base class for -// - MultiThreadExecutorWrapper -// - SingleThreadExecutorWrapper -// Platform must override bool submit(std::function) method. -class SubmittableExecutor : public Executor { - public: - ~SubmittableExecutor() override = default; - - template - Ptr> submit(Ptr> callable); - - protected: - // Submit a callable (with no delay). - // Returns true, if callable was submitted, false otherwise. - // Callable is not submitted if shutdown is in progress. - virtual bool DoSubmit(std::function wrapped_callable) = 0; -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_API_SUBMITTABLE_EXECUTOR_DEF_H_ diff --git a/cpp/platform/api/system_clock.h b/cpp/platform/api/system_clock.h index d85ae1ca..f319d7b2 100644 --- a/cpp/platform/api/system_clock.h +++ b/cpp/platform/api/system_clock.h @@ -1,19 +1,20 @@ #ifndef PLATFORM_API_SYSTEM_CLOCK_H_ #define PLATFORM_API_SYSTEM_CLOCK_H_ -#include +#include "platform/base/exception.h" +#include "absl/time/clock.h" namespace location { namespace nearby { -class SystemClock { +class SystemClock final { public: - virtual ~SystemClock() {} - - // Returns the time (in milliseconds) since the system was booted, and - // includes deep sleep. This clock should be guaranteed to be monotonic, and - // should continue to tick even when the CPU is in power saving modes. - virtual std::int64_t elapsedRealtime() = 0; + // Initialize global system state. + static void Init(); + // Returns current absolute time. It is guaranteed to be monotonic. + static absl::Time ElapsedRealtime(); + // Pauses current thread for the specified duration. + static Exception Sleep(absl::Duration duration); }; } // namespace nearby diff --git a/cpp/platform/api/thread_utils.h b/cpp/platform/api/thread_utils.h deleted file mode 100644 index e477662b..00000000 --- a/cpp/platform/api/thread_utils.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef PLATFORM_API_THREAD_UTILS_H_ -#define PLATFORM_API_THREAD_UTILS_H_ - -#include - -#include "platform/exception.h" - -namespace location { -namespace nearby { - -class ThreadUtils { - public: - virtual ~ThreadUtils() {} - - // https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#sleep(long) - virtual Exception::Value sleep( - std::int64_t millis) = 0; // throws Exception::INTERRUPTED -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_API_THREAD_UTILS_H_ diff --git a/cpp/platform/api/webrtc.h b/cpp/platform/api/webrtc.h index 39e09515..5b9bbf5d 100644 --- a/cpp/platform/api/webrtc.h +++ b/cpp/platform/api/webrtc.h @@ -1,45 +1,50 @@ #ifndef PLATFORM_API_WEBRTC_H_ #define PLATFORM_API_WEBRTC_H_ -#include +#include -#include "platform/byte_array.h" -#include "platform/ptr.h" +#include "proto/connections/offline_wire_formats.pb.h" +#include "proto/connections/offline_wire_formats.pb.h" +#include "platform/base/byte_array.h" +#include "absl/strings/string_view.h" #include "webrtc/api/peer_connection_interface.h" namespace location { namespace nearby { +namespace api { class WebRtcSignalingMessenger { public: + using OnSignalingMessageCallback = std::function; + virtual ~WebRtcSignalingMessenger() = default; - /** Called whenever we receive an inbox message from tachyon. */ - class SignalingMessageListener { - public: - virtual ~SignalingMessageListener() = default; + virtual bool SendMessage(absl::string_view peer_id, + const ByteArray& message) = 0; - virtual void onSignalingMessage(ConstPtr message) = 0; - }; - - class IceServersListener { - public: - virtual ~IceServersListener() = default; - - virtual void OnIceServersFetched( - std::vector> - ice_servers) = 0; - }; - - virtual bool registerSignaling() = 0; - virtual bool unregisterSignaling() = 0; - virtual bool sendMessage(const std::string& peer_id, - ConstPtr message) = 0; - virtual bool startReceivingMessages( - Ptr listener) = 0; - virtual void getIceServers(Ptr ice_servers_listener) = 0; + virtual bool StartReceivingMessages(OnSignalingMessageCallback listener) = 0; + virtual void StopReceivingMessages() = 0; }; +class WebRtcMedium { + public: + using PeerConnectionCallback = + std::function)>; + + virtual ~WebRtcMedium() = default; + + // Creates and returns a new webrtc::PeerConnectionInterface object via + // |callback|. + virtual void CreatePeerConnection(webrtc::PeerConnectionObserver* observer, + PeerConnectionCallback callback) = 0; + + // Returns a signaling messenger for sending WebRTC signaling messages. + virtual std::unique_ptr GetSignalingMessenger( + absl::string_view self_id, + const connections::LocationHint& location_hint) = 0; +}; + +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform/api/wifi.h b/cpp/platform/api/wifi.h index 6631d036..e0c5fb25 100644 --- a/cpp/platform/api/wifi.h +++ b/cpp/platform/api/wifi.h @@ -2,47 +2,49 @@ #define PLATFORM_API_WIFI_H_ #include +#include #include -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "absl/strings/string_view.h" namespace location { namespace nearby { +namespace api { // Possible authentication types for a WiFi network. -struct WifiAuthType { - enum Value { - UNKNOWN = 0, - OPEN = 1, - WPA_PSK = 2, - WEP = 3, - }; +enum class WifiAuthType { + // WiFi Authentication type; either none (non-secured a.k.a. open) link, or + // WPA PSK (WiFi Protected Access PreShared Key), or + // see https://en.wikipedia.org/wiki/Wi-Fi_Protected_Access + // WEP (Wired Equivalent Privacy); + // see https://en.wikipedia.org/wiki/Wired_Equivalent_Privacy + kUnknown = 0, + kOpen = 1, + kWpaPsk = 2, + kWep = 3, }; // Possible statuses of a device's connection to a WiFi network. -struct WifiConnectionStatus { - enum Value { - UNKNOWN = 0, - CONNECTED = 1, - CONNECTION_FAILURE = 2, - AUTH_FAILURE = 3, - }; +enum class WifiConnectionStatus { + kUnknown = 0, + kConnected = 1, + kConnectionFailure = 2, + kAuthFailure = 3, }; // Represents a WiFi network found during a call to WifiMedium#scan(). class WifiScanResult { public: - virtual ~WifiScanResult() {} + virtual ~WifiScanResult() = default; // Gets the SSID of this WiFi network. - virtual std::string getSSID() const = 0; + virtual std::string GetSsid() const = 0; // Gets the signal strength of this WiFi network in dBm. - virtual std::int32_t getSignalStrengthDbm() const = 0; + virtual std::int32_t GetSignalStrengthDbm() const = 0; // Gets the frequency band of this WiFi network in MHz. - virtual std::int32_t getFrequencyMhz() const = 0; + virtual std::int32_t GetFrequencyMhz() const = 0; // Gets the authentication type of this WiFi network. - virtual WifiAuthType::Value getAuthType() const = 0; + virtual WifiAuthType GetAuthType() const = 0; }; // Container of operations that can be performed over the WiFi medium. @@ -52,26 +54,22 @@ class WifiMedium { class ScanResultCallback { public: - virtual ~ScanResultCallback() {} + virtual ~ScanResultCallback() = default; - // The ConstPtr objects contained in scan_results will be - // owned (and destroyed) by the recipient of the callback methods (i.e. the - // creator of the concrete ScanResultCallback object). - virtual void onScanResults( - const std::vector>& scan_results) = 0; + virtual void OnScanResults( + const std::vector& scan_results) = 0; }; // Does not take ownership of the passed-in scan_result_callback -- destroying // that is up to the caller. - virtual bool scan(Ptr scan_result_callback) = 0; + virtual bool Scan(const ScanResultCallback& scan_result_callback) = 0; // If 'password' is an empty string, none has been provided. Returns // WifiConnectionStatus::CONNECTED on success, or the appropriate failure code // otherwise. - virtual WifiConnectionStatus::Value connectToNetwork( - const std::string& ssid, - const std::string& password, - WifiAuthType::Value auth_type) = 0; + virtual WifiConnectionStatus ConnectToNetwork(absl::string_view ssid, + absl::string_view password, + WifiAuthType auth_type) = 0; // Blocks until it's certain of there being a connection to the internet, or // returns false if it fails to do so. @@ -79,12 +77,13 @@ class WifiMedium { // How this method wants to verify said connection is totally up to it (so it // can feel free to ping whatever server, download whatever resource, etc. // that it needs to gain confidence that the internet is reachable hereon in). - virtual bool verifyInternetConnectivity() = 0; + virtual bool VerifyInternetConnectivity() = 0; // Returns the local device's IP address in the IPv4 dotted-quad format. - virtual std::string getIPAddress() = 0; + virtual std::string GetIpAddress() = 0; }; +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform/api/wifi_lan.h b/cpp/platform/api/wifi_lan.h index f282ba45..19b449f5 100644 --- a/cpp/platform/api/wifi_lan.h +++ b/cpp/platform/api/wifi_lan.h @@ -1,49 +1,61 @@ #ifndef PLATFORM_API_WIFI_LAN_H_ #define PLATFORM_API_WIFI_LAN_H_ -#include "platform/api/input_stream.h" -#include "platform/api/output_stream.h" -#include "platform/byte_array.h" -#include "platform/exception.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include + +#include "platform/base/byte_array.h" +#include "platform/base/input_stream.h" +#include "platform/base/listeners.h" +#include "platform/base/output_stream.h" #include "absl/strings/string_view.h" namespace location { namespace nearby { +namespace api { -// Opaque wrapper over a WifiLan service which contains encoded service name. +// Opaque wrapper over a WifiLan service which contains packed +// |WifiLanServiceInfo| string name. class WifiLanService { public: virtual ~WifiLanService() = default; - virtual std::string GetName() = 0; + // Returns the packed string of |WifiLanServiceInfo|. Note that the packed + // string would not include TXTRecord, which inheritor should save it in + // another store. + virtual std::string GetServiceName() const = 0; + + // Returns the packed string of endpoint info with named key. + virtual std::string GetTxtRecord(const std::string& key) const = 0; + + // Returns the local device's as a pair. + // IP address is in byte sequence, in network order. + virtual std::pair GetServiceAddress() const = 0; }; class WifiLanSocket { public: virtual ~WifiLanSocket() = default; - // Returns the InputStream of the WifiLanSocket, or a null Ptr - // on error. + // Returns the InputStream of the WifiLanSocket. + // On error, returned stream will report Exception::kIo on any operation. // - // The returned Ptr is not owned by the caller, and can be invalidated once + // The returned object is not owned by the caller, and can be invalidated once // the WifiLanSocket object is destroyed. - virtual Ptr GetInputStream() = 0; + virtual InputStream& GetInputStream() = 0; - // Returns the OutputStream of the WifiLanSocket, or a null - // Ptr on error. + // Returns the OutputStream of the WifiLanSocket. + // On error, returned stream will report Exception::kIo on any operation. // - // The returned Ptr is not owned by the caller, and can be invalidated once + // The returned object is not owned by the caller, and can be invalidated once // the WifiLanSocket object is destroyed. - virtual Ptr GetOutputStream() = 0; + virtual OutputStream& GetOutputStream() = 0; - // Returns Exception::IO on error, Exception::NONE otherwise. - virtual Exception::Value Close() = 0; + // Returns Exception::kIo on error, Exception::kSuccess otherwise. + virtual Exception Close() = 0; - // The returned Ptr is not owned by the caller, and can be invalidated once - // the WifiLanSocket object is destroyed. - virtual Ptr GetRemoteWifiLanService() = 0; + // Returns valid WifiLanService pointer if there is a connection, and + // nullptr otherwise. + virtual WifiLanService* GetRemoteWifiLanService() = 0; }; // Container of operations that can be performed over the WifiLan medium. @@ -52,44 +64,55 @@ class WifiLanMedium { virtual ~WifiLanMedium() = default; virtual bool StartAdvertising( - absl::string_view service_id, - absl::string_view wifi_lan_service_info_name) = 0; - virtual void StopAdvertising(absl::string_view service_id) = 0; + const std::string& service_id, + const std::string& wifi_lan_service_info_name, + const std::string& endpoint_info_name) = 0; + virtual bool StopAdvertising(const std::string& service_id) = 0; - // Callback for WifiLan discover results. - class DiscoveredServiceCallback { - public: - virtual ~DiscoveredServiceCallback() = default; - - virtual void OnServiceDiscovered(Ptr wifi_lan_service) = 0; - virtual void OnServiceLost(Ptr wifi_lan_service) = 0; + // Callback that is invoked when a discovered service is found or lost. + struct DiscoveredServiceCallback { + std::function + service_discovered_cb = + DefaultCallback(); + std::function + service_lost_cb = + DefaultCallback(); }; - virtual bool StartDiscovery( - absl::string_view service_id, - Ptr discovered_service_callback) = 0; - virtual void StopDiscovery(absl::string_view service_id) = 0; + // Returns true once the WifiLan discovery has been initiated. + virtual bool StartDiscovery(const std::string& service_id, + DiscoveredServiceCallback callback) = 0; - class AcceptedConnectionCallback { - public: - virtual ~AcceptedConnectionCallback() = default; + // Returns true once WifiLan discovery for service_id is well and truly + // stopped; after this returns, there must be no more invocations of the + // DiscoveredServiceCallback passed in to StartDiscovery() for service_id. + virtual bool StopDiscovery(const std::string& service_id) = 0; - // The Ptr provided in this callback method will be owned (and - // destroyed) by the recipient of the callback methods (i.e. the creator of - // the concrete AcceptedConnectionCallback object). - virtual void OnConnectionAccepted(Ptr socket, - absl::string_view service_id) = 0; + // Callback that is invoked when a new connection is accepted. + struct AcceptedConnectionCallback { + std::function + accepted_cb = DefaultCallback(); }; + // Returns true once WifiLan socket connection requests to service_id can be + // accepted. virtual bool StartAcceptingConnections( - absl::string_view service_id, - Ptr accepted_connection_callback) = 0; - virtual void StopAcceptingConnections(absl::string_view service_id) = 0; + const std::string& service_id, AcceptedConnectionCallback callback) = 0; + virtual bool StopAcceptingConnections(const std::string& service_id) = 0; - virtual Ptr Connect(Ptr wifi_lan_service, - absl::string_view service_id) = 0; + // Connects to a WifiLan service. + // On success, returns a new WifiLanSocket. + // On error, returns nullptr. + virtual std::unique_ptr Connect( + WifiLanService& service, const std::string& service_id) = 0; + + virtual WifiLanService* FindRemoteService(const std::string& ip_address, + int port) = 0; }; +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform/atomic_reference_test.cc b/cpp/platform/atomic_reference_test.cc deleted file mode 100644 index 58df5fc3..00000000 --- a/cpp/platform/atomic_reference_test.cc +++ /dev/null @@ -1,80 +0,0 @@ -#include "platform/api/atomic_reference.h" - -#include "platform/api/platform.h" -#include "platform/ptr.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -namespace location { -namespace nearby { -namespace { - -struct BigSizedStruct { - int data[100]{}; -}; - -enum TestEnum { - kValue1 = 1, - kValue2 = 2, -}; - -enum class ScopedTestEnum { - kValue1 = 1, - kValue2 = 2, -}; - -bool operator==(const BigSizedStruct& a, const BigSizedStruct& b) { - return memcmp(a.data, b.data, sizeof(BigSizedStruct::data)) == 0; -} - -bool operator!=(const BigSizedStruct& a, const BigSizedStruct& b) { - return !(a == b); -} - -} // namespace - -TEST(AtomicReferenceTest, SupportIntegralTypes) { - auto p = platform::ImplementationPlatform::createAtomicReference(); - p->set(5); - ASSERT_EQ(p->get(), 5); -} - -TEST(AtomicReferenceTest, SupportEnum) { - auto p = platform::ImplementationPlatform::createAtomicReference(); - p->set(TestEnum::kValue1); - ASSERT_EQ(p->get(), TestEnum::kValue1); -} - -TEST(AtomicReferenceTest, SupportScopedEnum) { - auto p = - platform::ImplementationPlatform::createAtomicReference(); - p->set(ScopedTestEnum::kValue1); - ASSERT_EQ(p->get(), ScopedTestEnum::kValue1); -} - -TEST(AtomicReferenceTest, SetTakesCopyOfValue) { - // Default constructor is zero-initalizing all data in BigSizedStruct. - BigSizedStruct v1; - auto p = platform::ImplementationPlatform::createAtomicReference< - BigSizedStruct>(); - v1.data[0] = 5; // Changing value before calling set() will affect stored - v1.data[7] = 3; // value. - p->set(v1); - v1.data[1] = 6; // Changing value after calling set() will not affect stored - v1.data[5] = 4; // value. - BigSizedStruct v2 = p->get(); - ASSERT_NE(v1, v2); - v1.data[1] = 0; - v1.data[5] = 0; - ASSERT_EQ(v2, v1); -} - -TEST(AtomicReferenceTest, SupportObjects) { - std::string s{"test"}; - auto ref = - platform::ImplementationPlatform::createAtomicReference(s); - ASSERT_EQ(s, ref->get()); -} - -} // namespace nearby -} // namespace location diff --git a/cpp/platform_v2/base/BUILD b/cpp/platform/base/BUILD similarity index 71% rename from cpp/platform_v2/base/BUILD rename to cpp/platform/base/BUILD index f9d16585..bc7a65c2 100644 --- a/cpp/platform_v2/base/BUILD +++ b/cpp/platform/base/BUILD @@ -23,9 +23,10 @@ cc_library( "types.h", ], visibility = [ - "//core_v2:__subpackages__", - "//platform_v2:__subpackages__", - "//platform_v2/api:__subpackages__", + "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", + "//core:__subpackages__", + "//platform:__subpackages__", + "//platform/api:__subpackages__", ], deps = [ "//absl/meta:type_traits", @@ -47,13 +48,14 @@ cc_library( "base_pipe.h", ], visibility = [ - "//core_v2:__subpackages__", - "//platform_v2/impl:__subpackages__", - "//platform_v2/public:__pkg__", + "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", + "//core:__subpackages__", + "//platform/impl:__subpackages__", + "//platform/public:__pkg__", ], deps = [ ":base", - "//platform_v2/api:types", + "//platform/api:types", "//absl/base:core_headers", ], ) @@ -64,11 +66,12 @@ cc_library( "logging.h", ], visibility = [ - "//platform_v2:__subpackages__", + "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", + "//platform:__subpackages__", ], deps = [ - "//platform_v2/api:platform", - "//platform_v2/api:types", + "//platform/api:platform", + "//platform/api:types", ], ) @@ -82,15 +85,15 @@ cc_library( "medium_environment.h", ], visibility = [ - "//core_v2:__subpackages__", - "//platform_v2/impl:__subpackages__", - "//platform_v2/public:__pkg__", + "//core:__subpackages__", + "//platform/impl:__subpackages__", + "//platform/public:__pkg__", ], deps = [ ":base", ":logging", - "//platform_v2/api:comm", - "//platform_v2/public:types", + "//platform/api:comm", + "//platform/public:types", "//absl/container:flat_hash_map", "//absl/strings", ], diff --git a/cpp/platform_v2/base/base64_utils.cc b/cpp/platform/base/base64_utils.cc similarity index 87% rename from cpp/platform_v2/base/base64_utils.cc rename to cpp/platform/base/base64_utils.cc index dfedf417..6053291a 100644 --- a/cpp/platform_v2/base/base64_utils.cc +++ b/cpp/platform/base/base64_utils.cc @@ -1,6 +1,6 @@ -#include "platform_v2/base/base64_utils.h" +#include "platform/base/base64_utils.h" -#include "platform_v2/base/byte_array.h" +#include "platform/base/byte_array.h" #include "absl/strings/escaping.h" namespace location { diff --git a/cpp/platform_v2/base/base64_utils.h b/cpp/platform/base/base64_utils.h similarity index 62% rename from cpp/platform_v2/base/base64_utils.h rename to cpp/platform/base/base64_utils.h index a5398c4d..87479761 100644 --- a/cpp/platform_v2/base/base64_utils.h +++ b/cpp/platform/base/base64_utils.h @@ -1,7 +1,7 @@ -#ifndef PLATFORM_V2_BASE_BASE64_UTILS_H_ -#define PLATFORM_V2_BASE_BASE64_UTILS_H_ +#ifndef PLATFORM_BASE_BASE64_UTILS_H_ +#define PLATFORM_BASE_BASE64_UTILS_H_ -#include "platform_v2/base/byte_array.h" +#include "platform/base/byte_array.h" #include "absl/strings/string_view.h" namespace location { @@ -16,4 +16,4 @@ class Base64Utils { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_BASE_BASE64_UTILS_H_ +#endif // PLATFORM_BASE_BASE64_UTILS_H_ diff --git a/cpp/platform_v2/base/base_input_stream.cc b/cpp/platform/base/base_input_stream.cc similarity index 98% rename from cpp/platform_v2/base/base_input_stream.cc rename to cpp/platform/base/base_input_stream.cc index 7c78bb36..257821f8 100644 --- a/cpp/platform_v2/base/base_input_stream.cc +++ b/cpp/platform/base/base_input_stream.cc @@ -1,4 +1,4 @@ -#include "platform_v2/base/base_input_stream.h" +#include "platform/base/base_input_stream.h" namespace location { namespace nearby { diff --git a/cpp/platform_v2/base/base_input_stream.h b/cpp/platform/base/base_input_stream.h similarity index 77% rename from cpp/platform_v2/base/base_input_stream.h rename to cpp/platform/base/base_input_stream.h index c155e7c9..e3414243 100644 --- a/cpp/platform_v2/base/base_input_stream.h +++ b/cpp/platform/base/base_input_stream.h @@ -1,9 +1,9 @@ -#ifndef PLATFORM_V2_BASE_BASE_INPUT_STREAM_H_ -#define PLATFORM_V2_BASE_BASE_INPUT_STREAM_H_ +#ifndef PLATFORM_BASE_BASE_INPUT_STREAM_H_ +#define PLATFORM_BASE_BASE_INPUT_STREAM_H_ -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/exception.h" -#include "platform_v2/base/input_stream.h" +#include "platform/base/byte_array.h" +#include "platform/base/exception.h" +#include "platform/base/input_stream.h" namespace location { namespace nearby { @@ -40,4 +40,4 @@ class BaseInputStream : public InputStream { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_BASE_BASE_INPUT_STREAM_H_ +#endif // PLATFORM_BASE_BASE_INPUT_STREAM_H_ diff --git a/cpp/platform_v2/base/base_mutex_lock.h b/cpp/platform/base/base_mutex_lock.h similarity index 73% rename from cpp/platform_v2/base/base_mutex_lock.h rename to cpp/platform/base/base_mutex_lock.h index e48c45cc..f065e4f6 100644 --- a/cpp/platform_v2/base/base_mutex_lock.h +++ b/cpp/platform/base/base_mutex_lock.h @@ -1,7 +1,7 @@ -#ifndef PLATFORM_V2_BASE_BASE_MUTEX_LOCK_H_ -#define PLATFORM_V2_BASE_BASE_MUTEX_LOCK_H_ +#ifndef PLATFORM_BASE_BASE_MUTEX_LOCK_H_ +#define PLATFORM_BASE_BASE_MUTEX_LOCK_H_ -#include "platform_v2/api/mutex.h" +#include "platform/api/mutex.h" #include "absl/base/thread_annotations.h" namespace location { @@ -23,4 +23,4 @@ class ABSL_SCOPED_LOCKABLE BaseMutexLock final { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_BASE_BASE_MUTEX_LOCK_H_ +#endif // PLATFORM_BASE_BASE_MUTEX_LOCK_H_ diff --git a/cpp/platform_v2/base/base_pipe.cc b/cpp/platform/base/base_pipe.cc similarity index 94% rename from cpp/platform_v2/base/base_pipe.cc rename to cpp/platform/base/base_pipe.cc index bd20f935..bd210d4b 100644 --- a/cpp/platform_v2/base/base_pipe.cc +++ b/cpp/platform/base/base_pipe.cc @@ -1,8 +1,8 @@ -#include "platform_v2/base/base_pipe.h" +#include "platform/base/base_pipe.h" -#include "platform_v2/base/base_mutex_lock.h" -#include "platform_v2/base/input_stream.h" -#include "platform_v2/base/output_stream.h" +#include "platform/base/base_mutex_lock.h" +#include "platform/base/input_stream.h" +#include "platform/base/output_stream.h" namespace location { namespace nearby { diff --git a/cpp/platform_v2/base/base_pipe.h b/cpp/platform/base/base_pipe.h similarity index 90% rename from cpp/platform_v2/base/base_pipe.h rename to cpp/platform/base/base_pipe.h index f74b3646..35a2f4ae 100644 --- a/cpp/platform_v2/base/base_pipe.h +++ b/cpp/platform/base/base_pipe.h @@ -1,16 +1,16 @@ -#ifndef PLATFORM_V2_BASE_BASE_PIPE_H_ -#define PLATFORM_V2_BASE_BASE_PIPE_H_ +#ifndef PLATFORM_BASE_BASE_PIPE_H_ +#define PLATFORM_BASE_BASE_PIPE_H_ #include #include #include -#include "platform_v2/api/condition_variable.h" -#include "platform_v2/api/mutex.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/exception.h" -#include "platform_v2/base/input_stream.h" -#include "platform_v2/base/output_stream.h" +#include "platform/api/condition_variable.h" +#include "platform/api/mutex.h" +#include "platform/base/byte_array.h" +#include "platform/base/exception.h" +#include "platform/base/input_stream.h" +#include "platform/base/output_stream.h" #include "absl/base/thread_annotations.h" namespace location { @@ -125,4 +125,4 @@ class BasePipe { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_BASE_BASE_PIPE_H_ +#endif // PLATFORM_BASE_BASE_PIPE_H_ diff --git a/cpp/platform_v2/base/bluetooth_utils.cc b/cpp/platform/base/bluetooth_utils.cc similarity index 97% rename from cpp/platform_v2/base/bluetooth_utils.cc rename to cpp/platform/base/bluetooth_utils.cc index e3221878..937cd9fd 100644 --- a/cpp/platform_v2/base/bluetooth_utils.cc +++ b/cpp/platform/base/bluetooth_utils.cc @@ -1,4 +1,4 @@ -#include "platform_v2/base/bluetooth_utils.h" +#include "platform/base/bluetooth_utils.h" #include "absl/strings/escaping.h" #include "absl/strings/str_format.h" diff --git a/cpp/platform_v2/base/bluetooth_utils.h b/cpp/platform/base/bluetooth_utils.h similarity index 83% rename from cpp/platform_v2/base/bluetooth_utils.h rename to cpp/platform/base/bluetooth_utils.h index a8a8a20f..1c1f50af 100644 --- a/cpp/platform_v2/base/bluetooth_utils.h +++ b/cpp/platform/base/bluetooth_utils.h @@ -1,7 +1,7 @@ -#ifndef PLATFORM_V2_BASE_BLUETOOTH_UTILS_H_ -#define PLATFORM_V2_BASE_BLUETOOTH_UTILS_H_ +#ifndef PLATFORM_BASE_BLUETOOTH_UTILS_H_ +#define PLATFORM_BASE_BLUETOOTH_UTILS_H_ -#include "platform_v2/base/byte_array.h" +#include "platform/base/byte_array.h" #include "absl/strings/string_view.h" namespace location { @@ -29,4 +29,4 @@ class BluetoothUtils { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_BASE_BLUETOOTH_UTILS_H_ +#endif // PLATFORM_BASE_BLUETOOTH_UTILS_H_ diff --git a/cpp/platform_v2/base/bluetooth_utils_test.cc b/cpp/platform/base/bluetooth_utils_test.cc similarity index 98% rename from cpp/platform_v2/base/bluetooth_utils_test.cc rename to cpp/platform/base/bluetooth_utils_test.cc index 7cc6f53e..9c892d00 100644 --- a/cpp/platform_v2/base/bluetooth_utils_test.cc +++ b/cpp/platform/base/bluetooth_utils_test.cc @@ -1,4 +1,4 @@ -#include "platform_v2/base/bluetooth_utils.h" +#include "platform/base/bluetooth_utils.h" #include "gtest/gtest.h" diff --git a/cpp/platform_v2/base/byte_array.h b/cpp/platform/base/byte_array.h similarity index 96% rename from cpp/platform_v2/base/byte_array.h rename to cpp/platform/base/byte_array.h index 1cdaf118..788aff18 100644 --- a/cpp/platform_v2/base/byte_array.h +++ b/cpp/platform/base/byte_array.h @@ -1,5 +1,5 @@ -#ifndef PLATFORM_V2_BASE_BYTE_ARRAY_H_ -#define PLATFORM_V2_BASE_BYTE_ARRAY_H_ +#ifndef PLATFORM_BASE_BYTE_ARRAY_H_ +#define PLATFORM_BASE_BYTE_ARRAY_H_ #include #include @@ -95,4 +95,4 @@ inline bool operator<(const ByteArray& lhs, const ByteArray& rhs) { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_BASE_BYTE_ARRAY_H_ +#endif // PLATFORM_BASE_BYTE_ARRAY_H_ diff --git a/cpp/platform_v2/base/byte_array_test.cc b/cpp/platform/base/byte_array_test.cc similarity index 98% rename from cpp/platform_v2/base/byte_array_test.cc rename to cpp/platform/base/byte_array_test.cc index 3479c673..5228c9e9 100644 --- a/cpp/platform_v2/base/byte_array_test.cc +++ b/cpp/platform/base/byte_array_test.cc @@ -1,4 +1,4 @@ -#include "platform_v2/base/byte_array.h" +#include "platform/base/byte_array.h" #include diff --git a/cpp/platform_v2/base/callable.h b/cpp/platform/base/callable.h similarity index 76% rename from cpp/platform_v2/base/callable.h rename to cpp/platform/base/callable.h index 294c7244..b40c1af4 100644 --- a/cpp/platform_v2/base/callable.h +++ b/cpp/platform/base/callable.h @@ -1,9 +1,9 @@ -#ifndef PLATFORM_V2_BASE_CALLABLE_H_ -#define PLATFORM_V2_BASE_CALLABLE_H_ +#ifndef PLATFORM_BASE_CALLABLE_H_ +#define PLATFORM_BASE_CALLABLE_H_ #include -#include "platform_v2/base/exception.h" +#include "platform/base/exception.h" namespace location { namespace nearby { @@ -20,4 +20,4 @@ using Callable = std::function()>; } // namespace nearby } // namespace location -#endif // PLATFORM_V2_BASE_CALLABLE_H_ +#endif // PLATFORM_BASE_CALLABLE_H_ diff --git a/cpp/platform_v2/base/exception.h b/cpp/platform/base/exception.h similarity index 96% rename from cpp/platform_v2/base/exception.h rename to cpp/platform/base/exception.h index 382c5728..acfda70b 100644 --- a/cpp/platform_v2/base/exception.h +++ b/cpp/platform/base/exception.h @@ -1,5 +1,5 @@ -#ifndef PLATFORM_V2_BASE_EXCEPTION_H_ -#define PLATFORM_V2_BASE_EXCEPTION_H_ +#ifndef PLATFORM_BASE_EXCEPTION_H_ +#define PLATFORM_BASE_EXCEPTION_H_ #include @@ -95,4 +95,4 @@ class ExceptionOr { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_BASE_EXCEPTION_H_ +#endif // PLATFORM_BASE_EXCEPTION_H_ diff --git a/cpp/platform_v2/base/exception_test.cc b/cpp/platform/base/exception_test.cc similarity index 97% rename from cpp/platform_v2/base/exception_test.cc rename to cpp/platform/base/exception_test.cc index 92a6cdea..878cb26d 100644 --- a/cpp/platform_v2/base/exception_test.cc +++ b/cpp/platform/base/exception_test.cc @@ -1,8 +1,8 @@ -#include "platform_v2/base/exception.h" +#include "platform/base/exception.h" #include -#include "platform_v2/base/exception_test.nc.h" +#include "platform/base/exception_test.nc.h" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/cpp/platform_v2/base/input_stream.h b/cpp/platform/base/input_stream.h similarity index 68% rename from cpp/platform_v2/base/input_stream.h rename to cpp/platform/base/input_stream.h index a29786f1..0b1651f0 100644 --- a/cpp/platform_v2/base/input_stream.h +++ b/cpp/platform/base/input_stream.h @@ -1,10 +1,10 @@ -#ifndef PLATFORM_V2_BASE_INPUT_STREAM_H_ -#define PLATFORM_V2_BASE_INPUT_STREAM_H_ +#ifndef PLATFORM_BASE_INPUT_STREAM_H_ +#define PLATFORM_BASE_INPUT_STREAM_H_ #include -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/exception.h" +#include "platform/base/byte_array.h" +#include "platform/base/exception.h" namespace location { namespace nearby { @@ -25,4 +25,4 @@ class InputStream { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_BASE_INPUT_STREAM_H_ +#endif // PLATFORM_BASE_INPUT_STREAM_H_ diff --git a/cpp/platform_v2/base/listeners.h b/cpp/platform/base/listeners.h similarity index 77% rename from cpp/platform_v2/base/listeners.h rename to cpp/platform/base/listeners.h index 8be7193e..45d0b3d3 100644 --- a/cpp/platform_v2/base/listeners.h +++ b/cpp/platform/base/listeners.h @@ -1,5 +1,5 @@ -#ifndef PLATFORM_V2_BASE_LISTENERS_H_ -#define PLATFORM_V2_BASE_LISTENERS_H_ +#ifndef PLATFORM_BASE_LISTENERS_H_ +#define PLATFORM_BASE_LISTENERS_H_ #include @@ -17,4 +17,4 @@ constexpr std::function DefaultCallback() { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_BASE_LISTENERS_H_ +#endif // PLATFORM_BASE_LISTENERS_H_ diff --git a/cpp/platform_v2/base/logging.h b/cpp/platform/base/logging.h similarity index 92% rename from cpp/platform_v2/base/logging.h rename to cpp/platform/base/logging.h index 3bbf276c..46201356 100644 --- a/cpp/platform_v2/base/logging.h +++ b/cpp/platform/base/logging.h @@ -1,8 +1,8 @@ -#ifndef PLATFORM_V2_BASE_LOGGING_H_ -#define PLATFORM_V2_BASE_LOGGING_H_ +#ifndef PLATFORM_BASE_LOGGING_H_ +#define PLATFORM_BASE_LOGGING_H_ -#include "platform_v2/api/log_message.h" -#include "platform_v2/api/platform.h" +#include "platform/api/log_message.h" +#include "platform/api/platform.h" namespace location { namespace nearby { @@ -62,4 +62,4 @@ class LogMessageVoidify { NEARBY_LOG_IS_ON(severity) \ ? NEARBY_LOG_MESSAGE(severity)->Print(__VA_ARGS__) : (void)0 -#endif // PLATFORM_V2_BASE_LOGGING_H_ +#endif // PLATFORM_BASE_LOGGING_H_ diff --git a/cpp/platform_v2/base/medium_environment.cc b/cpp/platform/base/medium_environment.cc similarity index 98% rename from cpp/platform_v2/base/medium_environment.cc rename to cpp/platform/base/medium_environment.cc index daa06267..068dcd1a 100644 --- a/cpp/platform_v2/base/medium_environment.cc +++ b/cpp/platform/base/medium_environment.cc @@ -1,16 +1,16 @@ -#include "platform_v2/base/medium_environment.h" +#include "platform/base/medium_environment.h" #include #include #include #include -#include "platform_v2/api/ble.h" -#include "platform_v2/api/bluetooth_adapter.h" -#include "platform_v2/api/bluetooth_classic.h" -#include "platform_v2/api/wifi_lan.h" -#include "platform_v2/base/logging.h" -#include "platform_v2/public/count_down_latch.h" +#include "platform/api/ble.h" +#include "platform/api/bluetooth_adapter.h" +#include "platform/api/bluetooth_classic.h" +#include "platform/api/wifi_lan.h" +#include "platform/base/logging.h" +#include "platform/public/count_down_latch.h" namespace location { namespace nearby { @@ -504,10 +504,9 @@ void MediumEnvironment::UpdateWifiLanMediumForAdvertising( } NEARBY_LOG(INFO, "Update WifiLan medium for advertising: this=%p; medium=%p; " - "service_id=%s; name=%s; " - "enabled=%d", - this, &medium, service_id.c_str(), service.GetName().c_str(), - enabled); + "service_id=%s; name=%s; enabled=%d", + this, &medium, service_id.c_str(), + service.GetServiceName().c_str(), enabled); for (auto& medium_info : wifi_lan_mediums_) { auto& local_medium = medium_info.first; auto& info = medium_info.second; diff --git a/cpp/platform_v2/base/medium_environment.h b/cpp/platform/base/medium_environment.h similarity index 96% rename from cpp/platform_v2/base/medium_environment.h rename to cpp/platform/base/medium_environment.h index 826189d1..5642ab63 100644 --- a/cpp/platform_v2/base/medium_environment.h +++ b/cpp/platform/base/medium_environment.h @@ -1,14 +1,14 @@ -#ifndef PLATFORM_V2_BASE_MEDIUM_ENVIRONMENT_H_ -#define PLATFORM_V2_BASE_MEDIUM_ENVIRONMENT_H_ +#ifndef PLATFORM_BASE_MEDIUM_ENVIRONMENT_H_ +#define PLATFORM_BASE_MEDIUM_ENVIRONMENT_H_ #include -#include "platform_v2/api/bluetooth_adapter.h" -#include "platform_v2/api/bluetooth_classic.h" -#include "platform_v2/api/webrtc.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/listeners.h" -#include "platform_v2/public/single_thread_executor.h" +#include "platform/api/bluetooth_adapter.h" +#include "platform/api/bluetooth_classic.h" +#include "platform/api/webrtc.h" +#include "platform/base/byte_array.h" +#include "platform/base/listeners.h" +#include "platform/public/single_thread_executor.h" #include "absl/container/flat_hash_map.h" #include "absl/strings/string_view.h" @@ -295,4 +295,4 @@ class MediumEnvironment { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_BASE_MEDIUM_ENVIRONMENT_H_ +#endif // PLATFORM_BASE_MEDIUM_ENVIRONMENT_H_ diff --git a/cpp/platform_v2/base/output_stream.h b/cpp/platform/base/output_stream.h similarity index 71% rename from cpp/platform_v2/base/output_stream.h rename to cpp/platform/base/output_stream.h index f126e444..31888a84 100644 --- a/cpp/platform_v2/base/output_stream.h +++ b/cpp/platform/base/output_stream.h @@ -1,8 +1,8 @@ -#ifndef PLATFORM_V2_BASE_OUTPUT_STREAM_H_ -#define PLATFORM_V2_BASE_OUTPUT_STREAM_H_ +#ifndef PLATFORM_BASE_OUTPUT_STREAM_H_ +#define PLATFORM_BASE_OUTPUT_STREAM_H_ -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/exception.h" +#include "platform/base/byte_array.h" +#include "platform/base/exception.h" namespace location { namespace nearby { @@ -22,4 +22,4 @@ class OutputStream { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_BASE_OUTPUT_STREAM_H_ +#endif // PLATFORM_BASE_OUTPUT_STREAM_H_ diff --git a/cpp/platform_v2/base/payload_id.h b/cpp/platform/base/payload_id.h similarity index 54% rename from cpp/platform_v2/base/payload_id.h rename to cpp/platform/base/payload_id.h index 81f2e730..bbff17ce 100644 --- a/cpp/platform_v2/base/payload_id.h +++ b/cpp/platform/base/payload_id.h @@ -1,5 +1,5 @@ -#ifndef PLATFORM_V2_BASE_PAYLOAD_ID_H_ -#define PLATFORM_V2_BASE_PAYLOAD_ID_H_ +#ifndef PLATFORM_BASE_PAYLOAD_ID_H_ +#define PLATFORM_BASE_PAYLOAD_ID_H_ #include @@ -11,4 +11,4 @@ using PayloadId = std::int64_t; } // namespace nearby } // namespace location -#endif // PLATFORM_V2_BASE_PAYLOAD_ID_H_ +#endif // PLATFORM_BASE_PAYLOAD_ID_H_ diff --git a/cpp/platform_v2/base/prng.cc b/cpp/platform/base/prng.cc similarity index 97% rename from cpp/platform_v2/base/prng.cc rename to cpp/platform/base/prng.cc index ace2928c..364cfbbc 100644 --- a/cpp/platform_v2/base/prng.cc +++ b/cpp/platform/base/prng.cc @@ -1,4 +1,4 @@ -#include "platform_v2/base/prng.h" +#include "platform/base/prng.h" #include diff --git a/cpp/platform_v2/base/prng.h b/cpp/platform/base/prng.h similarity index 74% rename from cpp/platform_v2/base/prng.h rename to cpp/platform/base/prng.h index 8c915b89..9b2e7ebf 100644 --- a/cpp/platform_v2/base/prng.h +++ b/cpp/platform/base/prng.h @@ -1,5 +1,5 @@ -#ifndef PLATFORM_V2_BASE_PRNG_H_ -#define PLATFORM_V2_BASE_PRNG_H_ +#ifndef PLATFORM_BASE_PRNG_H_ +#define PLATFORM_BASE_PRNG_H_ #include @@ -20,4 +20,4 @@ class Prng { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_BASE_PRNG_H_ +#endif // PLATFORM_BASE_PRNG_H_ diff --git a/cpp/platform_v2/base/prng_test.cc b/cpp/platform/base/prng_test.cc similarity index 98% rename from cpp/platform_v2/base/prng_test.cc rename to cpp/platform/base/prng_test.cc index 4d4466e2..7298c48b 100644 --- a/cpp/platform_v2/base/prng_test.cc +++ b/cpp/platform/base/prng_test.cc @@ -1,4 +1,4 @@ -#include "platform_v2/base/prng.h" +#include "platform/base/prng.h" #include "gtest/gtest.h" diff --git a/cpp/platform_v2/base/runnable.h b/cpp/platform/base/runnable.h similarity index 75% rename from cpp/platform_v2/base/runnable.h rename to cpp/platform/base/runnable.h index 4b7a6898..09fe18b3 100644 --- a/cpp/platform_v2/base/runnable.h +++ b/cpp/platform/base/runnable.h @@ -1,5 +1,5 @@ -#ifndef PLATFORM_V2_BASE_RUNNABLE_H_ -#define PLATFORM_V2_BASE_RUNNABLE_H_ +#ifndef PLATFORM_BASE_RUNNABLE_H_ +#define PLATFORM_BASE_RUNNABLE_H_ #include @@ -16,4 +16,4 @@ using Runnable = std::function; } // namespace nearby } // namespace location -#endif // PLATFORM_V2_BASE_RUNNABLE_H_ +#endif // PLATFORM_BASE_RUNNABLE_H_ diff --git a/cpp/platform_v2/base/socket.h b/cpp/platform/base/socket.h similarity index 67% rename from cpp/platform_v2/base/socket.h rename to cpp/platform/base/socket.h index 41415083..1282947d 100644 --- a/cpp/platform_v2/base/socket.h +++ b/cpp/platform/base/socket.h @@ -1,8 +1,8 @@ -#ifndef PLATFORM_V2_BASE_SOCKET_H_ -#define PLATFORM_V2_BASE_SOCKET_H_ +#ifndef PLATFORM_BASE_SOCKET_H_ +#define PLATFORM_BASE_SOCKET_H_ -#include "platform_v2/base/input_stream.h" -#include "platform_v2/base/output_stream.h" +#include "platform/base/input_stream.h" +#include "platform/base/output_stream.h" namespace location { namespace nearby { @@ -22,4 +22,4 @@ class Socket { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_BASE_SOCKET_H_ +#endif // PLATFORM_BASE_SOCKET_H_ diff --git a/cpp/platform_v2/base/types.h b/cpp/platform/base/types.h similarity index 86% rename from cpp/platform_v2/base/types.h rename to cpp/platform/base/types.h index 1cca5f3f..c61d9666 100644 --- a/cpp/platform_v2/base/types.h +++ b/cpp/platform/base/types.h @@ -1,5 +1,5 @@ -#ifndef PLATFORM_V2_BASE_TYPES_H_ -#define PLATFORM_V2_BASE_TYPES_H_ +#ifndef PLATFORM_BASE_TYPES_H_ +#define PLATFORM_BASE_TYPES_H_ #include @@ -27,4 +27,4 @@ inline Derived down_cast(Base* value) { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_BASE_TYPES_H_ +#endif // PLATFORM_BASE_TYPES_H_ diff --git a/cpp/platform/base64_utils.cc b/cpp/platform/base64_utils.cc deleted file mode 100644 index 4ac6e6d6..00000000 --- a/cpp/platform/base64_utils.cc +++ /dev/null @@ -1,55 +0,0 @@ -#include "platform/base64_utils.h" - -#include "absl/strings/escaping.h" - -namespace location { -namespace nearby { - -std::string Base64Utils::encode(ConstPtr bytes) { - std::string base64_string; - - if (!bytes.isNull()) { - absl::WebSafeBase64Escape(std::string(bytes->getData(), bytes->size()), - &base64_string); - } - - return base64_string; -} - -std::string Base64Utils::encode(const ByteArray& bytes) { - std::string base64_string; - absl::WebSafeBase64Escape(std::string(bytes.getData(), bytes.size()), - &base64_string); - - return base64_string; -} - -std::string Base64Utils::encode(absl::string_view input) { - std::string base64_string; - absl::WebSafeBase64Escape(input, &base64_string); - - return base64_string; -} - -template<> -Ptr Base64Utils::decode(absl::string_view base64_string) { - std::string decoded_string; - if (!absl::WebSafeBase64Unescape(base64_string, &decoded_string)) { - return Ptr(); - } - - return MakePtr(new ByteArray(decoded_string.data(), decoded_string.size())); -} - -template<> -ByteArray Base64Utils::decode(absl::string_view base64_string) { - std::string decoded_string; - if (!absl::WebSafeBase64Unescape(base64_string, &decoded_string)) { - return ByteArray(); - } - - return ByteArray(decoded_string.data(), decoded_string.size()); -} - -} // namespace nearby -} // namespace location diff --git a/cpp/platform/base64_utils.h b/cpp/platform/base64_utils.h deleted file mode 100644 index cdfee91e..00000000 --- a/cpp/platform/base64_utils.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef PLATFORM_BASE64_UTILS_H_ -#define PLATFORM_BASE64_UTILS_H_ - -#include "platform/byte_array.h" -#include "platform/port/string.h" -#include "platform/ptr.h" -#include "absl/strings/string_view.h" - -namespace location { -namespace nearby { - -class Base64Utils { - public: - static std::string encode(absl::string_view input); - static std::string encode(const ByteArray& bytes); - static std::string encode(ConstPtr bytes); - - template - static T decode(absl::string_view base64_string); - template <> - Ptr decode(absl::string_view base64_string); - template <> - ByteArray decode(absl::string_view base64_string); - static Ptr decode(absl::string_view base64_string) { - return decode>(base64_string); - } -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_BASE64_UTILS_H_ diff --git a/cpp/platform/byte_array.h b/cpp/platform/byte_array.h deleted file mode 100644 index fba6ad08..00000000 --- a/cpp/platform/byte_array.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef PLATFORM_BYTE_ARRAY_H_ -#define PLATFORM_BYTE_ARRAY_H_ - -#include "platform/port/string.h" - -namespace location { -namespace nearby { - -class ByteArray { - public: - // Create an empty ByteArray - ByteArray() {} - - // Create ByteArray from string. - explicit ByteArray(const std::string& source) { - data_ = source; - } - - // Create default-initialized ByteArray of a given size. - explicit ByteArray(size_t size) { - setData(size); - } - - // Create value-initialized ByteArray of a given size. - ByteArray(const char* data, size_t size) { - setData(data, size); - } - - // Assign a new value to this ByteArray, as a copy of data, with a given size. - void setData(const char* data, size_t size) { - data_.assign(data, size); - } - - // Assign a new value of a given size to this ByteArray - // (as a repeated char value). - void setData(size_t size, char value = 0) { - data_.assign(size, value); - } - - char* getData() { return &data_[0]; } - const char* getData() const { return data_.data(); } - size_t size() const { return data_.size(); } - - // Operator overloads when comparing ConstPtr. - bool operator==(const ByteArray& rhs) const { - return this->size() == rhs.size() && - memcmp(this->getData(), rhs.getData(), this->size()) == 0; - } - bool operator!=(const ByteArray& rhs) const { return !(*this == rhs); } - bool operator<(const ByteArray& rhs) const { - if (this->size() != rhs.size()) { - return this->size() < rhs.size(); - } - return memcmp(this->getData(), rhs.getData(), this->size()) < 0; - } - // TODO(b/149869249) : rename according to go/c-style - std::string asString() const { return data_; } - - private: - std::string data_; -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_BYTE_ARRAY_H_ diff --git a/cpp/platform/byte_array_test.cc b/cpp/platform/byte_array_test.cc deleted file mode 100644 index 8bd5ee97..00000000 --- a/cpp/platform/byte_array_test.cc +++ /dev/null @@ -1,39 +0,0 @@ -#include "platform/byte_array.h" - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -namespace { - -using location::nearby::ByteArray; - -TEST(ByteArrayTest, DefaultSizeIsZero) { - ByteArray bytes; - ASSERT_EQ(0, bytes.size()); -} - -TEST(ByteArrayTest, SetFromString) { - std::string setup("setup_test"); - ByteArray bytes{setup}; // array initialized with a copy of string. - ASSERT_EQ(setup.size(), bytes.size()); - ASSERT_EQ(bytes.asString(), setup); -} - -TEST(ByteArrayTest, SetExplicitSize) { - constexpr size_t kArraySize = 10; - char reference[kArraySize]{}; - ByteArray bytes{kArraySize}; // array of size 10, zero-initialized. - ASSERT_EQ(kArraySize, bytes.size()); - ASSERT_EQ(0, memcmp(bytes.getData(), reference, kArraySize)); -} - -TEST(ByteArrayTest, SetExplicitData) { - constexpr static const char message[] {"test_message"}; - constexpr size_t kMessageSize = sizeof(message); - ByteArray bytes{message, kMessageSize}; - ASSERT_EQ(kMessageSize, bytes.size()); - ASSERT_NE(message, bytes.getData()); - ASSERT_EQ(0, memcmp(message, bytes.getData(), kMessageSize)); -} - -} // namespace diff --git a/cpp/platform/callable.h b/cpp/platform/callable.h deleted file mode 100644 index 792a207d..00000000 --- a/cpp/platform/callable.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef PLATFORM_CALLABLE_H_ -#define PLATFORM_CALLABLE_H_ - -#include "platform/exception.h" - -namespace location { -namespace nearby { - -// The Callable interface should be implemented by any class whose instances are -// intended to be executed by a thread, and need to return a result. The class -// must define a method named call() with no arguments and a specific return -// type. -// -// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Callable.html -template -class Callable { - public: - virtual ~Callable() {} - - virtual ExceptionOr call() = 0; -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_CALLABLE_H_ diff --git a/cpp/platform/cancelable.h b/cpp/platform/cancelable.h deleted file mode 100644 index 74a2d634..00000000 --- a/cpp/platform/cancelable.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef PLATFORM_CANCELABLE_H_ -#define PLATFORM_CANCELABLE_H_ - -namespace location { -namespace nearby { - -// An interface to provide a cancellation mechanism for objects that represent -// long-running operations. -class Cancelable { - public: - virtual ~Cancelable() {} - - virtual bool cancel() = 0; -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_CANCELABLE_H_ diff --git a/cpp/platform/cancelable_alarm.cc b/cpp/platform/cancelable_alarm.cc deleted file mode 100644 index bb5fd90d..00000000 --- a/cpp/platform/cancelable_alarm.cc +++ /dev/null @@ -1,39 +0,0 @@ -#include "platform/cancelable_alarm.h" - -#include "platform/api/platform.h" -#include "platform/api/scheduled_executor.h" -#include "platform/synchronized.h" - -namespace location { -namespace nearby { - -namespace { -using Platform = platform::ImplementationPlatform; -} - -CancelableAlarm::CancelableAlarm(const std::string &name, - Ptr runnable, - std::int64_t delay_millis, - Ptr scheduled_executor) - : name_(name), - lock_(Platform::createLock()), - cancelable_(scheduled_executor->schedule(runnable, delay_millis)) {} - -CancelableAlarm::~CancelableAlarm() { cancelable_.destroy(); } - -bool CancelableAlarm::cancel() { - Synchronized s(lock_.get()); - - if (cancelable_.isNull()) { - // TODO(tracyzhou): Add logging - return false; - } - - bool canceled = cancelable_->cancel(); - // TODO(tracyzhou): Add logging - cancelable_.destroy(); - return canceled; -} - -} // namespace nearby -} // namespace location diff --git a/cpp/platform/cancelable_alarm.h b/cpp/platform/cancelable_alarm.h deleted file mode 100644 index e8e317c1..00000000 --- a/cpp/platform/cancelable_alarm.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef PLATFORM_CANCELABLE_ALARM_H_ -#define PLATFORM_CANCELABLE_ALARM_H_ - -#include - -#include "platform/api/lock.h" -#include "platform/api/scheduled_executor.h" -#include "platform/cancelable.h" -#include "platform/port/string.h" -#include "platform/ptr.h" -#include "platform/runnable.h" - -namespace location { -namespace nearby { - -/** - * A cancelable alarm with a name. This is a simple wrapper around the logic - * for posting a Runnable on a ScheduledExecutor and (possibly) later - * canceling it. - */ -class CancelableAlarm { - public: - CancelableAlarm(const std::string& name, Ptr runnable, - std::int64_t delay_millis, - Ptr scheduled_executor); - ~CancelableAlarm(); - - bool cancel(); - - private: - std::string name_; - ScopedPtr > lock_; - Ptr cancelable_; -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_CANCELABLE_ALARM_H_ diff --git a/cpp/platform_v2/config/BUILD b/cpp/platform/config/BUILD similarity index 100% rename from cpp/platform_v2/config/BUILD rename to cpp/platform/config/BUILD diff --git a/cpp/platform/port/config.h b/cpp/platform/config/config.h similarity index 81% rename from cpp/platform/port/config.h rename to cpp/platform/config/config.h index 841168b0..b32169fc 100644 --- a/cpp/platform/port/config.h +++ b/cpp/platform/config/config.h @@ -1,5 +1,5 @@ -#ifndef PLATFORM_PORT_CONFIG_H_ -#define PLATFORM_PORT_CONFIG_H_ +#ifndef PLATFORM_CONFIG_CONFIG_H_ +#define PLATFORM_CONFIG_CONFIG_H_ // Clients can modify this file to customize the Nearby C++ codebase as per // their particular constraints and environments. @@ -19,4 +19,4 @@ #define NEARBY_USE_RTTI 1 #endif -#endif // PLATFORM_PORT_CONFIG_H_ +#endif // PLATFORM_CONFIG_CONFIG_H_ diff --git a/cpp/platform/config/string.h b/cpp/platform/config/string.h new file mode 100644 index 00000000..fe3b9a9a --- /dev/null +++ b/cpp/platform/config/string.h @@ -0,0 +1,12 @@ +#ifndef PLATFORM_CONFIG_STRING_H_ +#define PLATFORM_CONFIG_STRING_H_ + +#include + +#include "platform/config/config.h" + +#if NEARBY_USE_STD_STRING +using std::string; +#endif + +#endif // PLATFORM_CONFIG_STRING_H_ diff --git a/cpp/platform/container_of.h b/cpp/platform/container_of.h deleted file mode 100644 index ccdccd7a..00000000 --- a/cpp/platform/container_of.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef PLATFORM_CONTAINER_OF_H_ -#define PLATFORM_CONTAINER_OF_H_ - -#include -#include - -namespace location::nearby { - -// Similar to offsetof() macro, but implemented in a type-safe way, -// OffsetOf() returns the byte offset of a given data -// member in the ClassType. -// Behavior is undefined if member is not a direct, non-static data member of -// type ClassType. -// usage example: -// struct S { int x; double y; }; -// size_t y_offset = OffsetOf(&S::y); -// CHECK(y_offset >= sizeof(int)); -// -// the following is not guaranteed to work: -// struct S1 { int x; }; -// struct S2 { double y; }; -// struct S : public S1, S2 { char t; }; -// size_t y_offset_bad = OffsetOf(&S::y); -// because S::y is not a direct member of S; it is a member by inheritance. -// To make sure OffsetOf works with inherited members, it must be called -// with explicitly defined template parameters, as follows: -// size_t y_offset_ok = OffsetOf(&S::y); -// -// However, the following is guaranteed to work: -// struct S1 { int x; }; -// struct S2 { double y; }; -// struct S3 { double z; }; -// struct S : public S1, S2 { S3 s3; char t; }; -// size_t s3_offset = OffsetOf(&S::s3); - -template -constexpr size_t OffsetOf(const ValueType ClassType::*member) { - std::aligned_storage_t obj_memory; - ClassType* obj = reinterpret_cast(&obj_memory); - return reinterpret_cast(&(obj->*member)) - - reinterpret_cast(obj); -} - -// Similar to Linux containerof() macro, this function returns pointer to -// the type instance that contains the specified member; -// ContainerOf(, ); -// usage example: -// struct S { int x; double y; } a; -// S *b = ContainerOf(&a.y, &S::y); -// CHECK(b == &a); -template -ClassType* ContainerOf(ValueType* ptr, ValueType ClassType::*member) { - using BaseValueType = std::remove_volatile_t; - return reinterpret_cast( - reinterpret_cast(const_cast(ptr)) - - OffsetOf(member)); -} - -template -const ClassType* ContainerOf(const ValueType* ptr, - ValueType ClassType::*member) { - using BaseValueType = std::remove_volatile_t; - return reinterpret_cast( - reinterpret_cast(const_cast(ptr)) - - OffsetOf(member)); -} - -} // namespace location::nearby - -#endif // PLATFORM_CONTAINER_OF_H_ diff --git a/cpp/platform/container_of_test.cc b/cpp/platform/container_of_test.cc deleted file mode 100644 index 72c5d8c6..00000000 --- a/cpp/platform/container_of_test.cc +++ /dev/null @@ -1,47 +0,0 @@ -#include "platform/container_of.h" - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -namespace location::nearby { - -TEST(OffsetOf, OffsetOfTest) { - struct [[gnu::packed]] S { - char x; - double y; - }; - EXPECT_EQ(OffsetOf(&S::x), 0U); - EXPECT_EQ(OffsetOf(&S::y), sizeof(S::x)); -} - -TEST(OffsetOf, ExplicitOffsetOfTest) { - struct [[gnu::packed]] S1 { int x; }; - struct [[gnu::packed]] S2 { double y; }; - struct [[gnu::packed]] S : public S1, S2 { char t; }; - EXPECT_EQ((OffsetOf().x), S>(&S::x)), 0U); - EXPECT_EQ((OffsetOf().y), S>(&S::y)), sizeof(S::x)); -} - -TEST(ContainerOf, ContainerOfTest) { - struct [[gnu::packed]] S { - char x; - double y; - } s; - char* p = &s.x; - double* q = &s.y; - EXPECT_EQ(ContainerOf(p, &S::x), &s); - EXPECT_EQ(ContainerOf(q, &S::y), &s); -} - -TEST(ContainerOf, ContainerOfTestConst) { - struct [[gnu::packed]] S { - char x; - double y; - } s; - const char* p = &s.x; - const double* q = &s.y; - EXPECT_EQ(ContainerOf(p, &S::x), &s); - EXPECT_EQ(ContainerOf(q, &S::y), &s); -} - -} // namespace location::nearby diff --git a/cpp/platform/exception.h b/cpp/platform/exception.h deleted file mode 100644 index 01b333e8..00000000 --- a/cpp/platform/exception.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef PLATFORM_EXCEPTION_H_ -#define PLATFORM_EXCEPTION_H_ - -#include - -namespace location { -namespace nearby { - -struct Exception { - enum Value : int { - NONE, - IO, - INTERRUPTED, - INVALID_PROTOCOL_BUFFER, - EXECUTION, - // New code should use the kConstants. - // Old CONSTANTS are deprecated, and should not be used. - kFailed = -1, // Initial value of Exception; any unknown error. - kSuccess = NONE, // No exception. - kIo = IO, // IO Error happened. - kInterrupted = INTERRUPTED, // Operation was interrupted. - kInvalidProtocolBuffer = INVALID_PROTOCOL_BUFFER, // Couldn't parse. - kExecution = EXECUTION, // Couldn't execute. - kTimeout, // Operation did not finish within specified time. - }; - Value value {kFailed}; -}; - -// ExceptionOr provides experience similar to StatusOr used in -// Google Cloud API, see: -// https://googleapis.github.io/google-cloud-cpp/0.7.0/common/status__or_8h_source.html -// -// If ok() returns true, result() is a usable return value. Otherwise, -// exception() explains why such a value is not present. -// -// A typical pattern of usage is as follows: -// -// if (!e.ok()) { -// if (Exception::EXCEPTION_TYPE_1 == e.exception()) { -// // Handle Exception::EXCEPTION_TYPE_1. -// } else if (Exception::EXCEPTION_TYPE_2 == e.exception()) { -// // Handle Exception::EXCEPTION_TYPE_2. -// } -// -// return; -// } -// -// // Use e.result(). -template -class ExceptionOr { - public: - ExceptionOr() = default; - ExceptionOr(T&& result) : result_{std::move(result)}, // NOLINT - exception_{Exception::kSuccess} {} - ExceptionOr(const T& result) : result_{result}, // NOLINT - exception_{Exception::kSuccess} {} - ExceptionOr(Exception::Value exception) : exception_{exception} {} // NOLINT - - bool ok() const { return exception_.value == Exception::kSuccess; } - - T& result() & { return result_; } - const T& result() const & { return result_; } - T&& result() && { return std::move(result_); } - const T&& result() const && { return std::move(result_); } - - Exception::Value exception() const { return exception_.value; } - - T GetResult() const; - Exception GetException() const; - - private: - T result_; - Exception exception_ {Exception::kFailed}; -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_EXCEPTION_H_ diff --git a/cpp/platform/exception_test.cc b/cpp/platform/exception_test.cc deleted file mode 100644 index d36e2d85..00000000 --- a/cpp/platform/exception_test.cc +++ /dev/null @@ -1,76 +0,0 @@ -#include "platform/exception.h" - -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -namespace location::nearby { - -TEST(ExceptionOr, Result_Copy_NonConst) { - ExceptionOr> exception_or_vector({1, 2, 3}); - EXPECT_FALSE(exception_or_vector.result().empty()); - - // Expect a copy when not explicitly moving the result. - std::vector copy = exception_or_vector.result(); - EXPECT_FALSE(copy.empty()); - EXPECT_FALSE(exception_or_vector.result().empty()); - - // Modifying |exception_or_vector| should not affect the copy. - exception_or_vector.result().clear(); - EXPECT_FALSE(copy.empty()); -} - -TEST(ExceptionOr, Result_Copy_Const) { - const ExceptionOr> exception_or_vector({1, 2, 3}); - EXPECT_FALSE(exception_or_vector.result().empty()); - - // Expect a copy when not explicitly moving the result. - std::vector copy = exception_or_vector.result(); - EXPECT_FALSE(copy.empty()); - EXPECT_FALSE(exception_or_vector.result().empty()); -} - -TEST(ExceptionOr, Result_Reference_NonConst) { - ExceptionOr> exception_or_vector({1, 2, 3}); - EXPECT_FALSE(exception_or_vector.result().empty()); - - // Getting a reference should not modify the source. - std::vector& reference = exception_or_vector.result(); - EXPECT_FALSE(reference.empty()); - EXPECT_FALSE(exception_or_vector.result().empty()); - - // Modifying |exception_or_vector| should reflect in the reference. - exception_or_vector.result().clear(); - EXPECT_TRUE(reference.empty()); -} - -TEST(ExceptionOr, Result_Reference_Const) { - const ExceptionOr> exception_or_vector({1, 2, 3}); - EXPECT_FALSE(exception_or_vector.result().empty()); - - // Getting a reference should not modify the source. - const std::vector& reference = exception_or_vector.result(); - EXPECT_FALSE(reference.empty()); - EXPECT_FALSE(exception_or_vector.result().empty()); -} - -TEST(ExceptionOr, Result_Move_NonConst) { - ExceptionOr> exception_or_vector({1, 2, 3}); - ASSERT_FALSE(exception_or_vector.result().empty()); - - // Moving the result should clear the source. - std::vector moved = std::move(exception_or_vector).result(); - ASSERT_FALSE(moved.empty()); -} - -TEST(ExceptionOr, Result_Move_Const) { - const ExceptionOr> exception_or_vector({1, 2, 3}); - ASSERT_FALSE(exception_or_vector.result().empty()); - - // Moving const rvalue reference will result in a copy. - std::vector moved = std::move(exception_or_vector).result(); - ASSERT_FALSE(moved.empty()); -} - -} // namespace location::nearby diff --git a/cpp/platform/impl/g3/BUILD b/cpp/platform/impl/g3/BUILD index ddb412ed..aeb3a320 100644 --- a/cpp/platform/impl/g3/BUILD +++ b/cpp/platform/impl/g3/BUILD @@ -1,26 +1,110 @@ +cc_library( + name = "types", + testonly = True, + srcs = [ + "log_message.cc", + "scheduled_executor.cc", + "system_clock.cc", + ], + hdrs = [ + "atomic_boolean.h", + "atomic_reference.h", + "condition_variable.h", + "count_down_latch.h", + "log_message.h", + "multi_thread_executor.h", + "mutex.h", + "pipe.h", + "scheduled_executor.h", + "single_thread_executor.h", + ], + visibility = ["//visibility:private"], + deps = [ + "//base", + "//platform/api:platform", + "//platform/api:types", + "//platform/base", + "//platform/base:util", + "//platform/impl/shared:posix_mutex", + "//absl/base:core_headers", + "//absl/synchronization", + "//absl/time", + "//thread", + ], +) + +cc_library( + name = "comm", + testonly = True, + srcs = [ + "ble.cc", + "bluetooth_adapter.cc", + "bluetooth_classic.cc", + "webrtc.cc", + "wifi_lan.cc", + ], + hdrs = [ + "ble.h", + "bluetooth_adapter.h", + "bluetooth_classic.h", + "webrtc.h", + "wifi_lan.h", + ], + visibility = ["//visibility:private"], + deps = [ + ":types", + "//platform/api:comm", + "//platform/base", + "//platform/base:logging", + "//platform/base:test_util", + "//absl/base:core_headers", + "//absl/container:flat_hash_map", + "//absl/container:flat_hash_set", + "//absl/strings", + "//absl/synchronization", + "//webrtc/api:create_peerconnection_factory", #buildcleaner: keep + "//webrtc/api:libjingle_peerconnection_api", + "//webrtc/api/task_queue:default_task_queue_factory", + ], +) + +cc_library( + name = "crypto", + testonly = True, + srcs = [ + "crypto.cc", + ], + visibility = ["//visibility:private"], + deps = [ + "//platform/api:types", + "//platform/base", + "//absl/strings", + "//openssl:crypto", + ], +) + cc_library( name = "g3", + testonly = True, srcs = [ - "atomic_reference_impl.h", "platform.cc", - "settable_future_impl.h", - "system_clock_impl.h", ], visibility = [ "//core:__subpackages__", "//platform:__subpackages__", ], deps = [ - "//platform:types", - "//platform/api", - "//platform/impl/shared:atomic_boolean", + ":comm", + ":crypto", # build_cleaner: keep + ":types", + "//platform/api:comm", + "//platform/api:platform", + "//platform/api:types", + "//platform/base:test_util", "//platform/impl/shared:file", - "//platform/impl/shared:posix_condition_variable", - "//platform/impl/shared:posix_lock", - "//platform/port:string", "//absl/base:core_headers", - "//absl/synchronization", + "//absl/memory", + "//absl/strings", "//absl/time", - "//absl/types:any", ], ) diff --git a/cpp/platform_v2/impl/g3/atomic_boolean.h b/cpp/platform/impl/g3/atomic_boolean.h similarity index 72% rename from cpp/platform_v2/impl/g3/atomic_boolean.h rename to cpp/platform/impl/g3/atomic_boolean.h index f43a2bcf..2970102a 100644 --- a/cpp/platform_v2/impl/g3/atomic_boolean.h +++ b/cpp/platform/impl/g3/atomic_boolean.h @@ -1,16 +1,16 @@ -#ifndef PLATFORM_V2_IMPL_G3_ATOMIC_BOOLEAN_H_ -#define PLATFORM_V2_IMPL_G3_ATOMIC_BOOLEAN_H_ +#ifndef PLATFORM_IMPL_G3_ATOMIC_BOOLEAN_H_ +#define PLATFORM_IMPL_G3_ATOMIC_BOOLEAN_H_ #include -#include "platform_v2/api/atomic_boolean.h" +#include "platform/api/atomic_boolean.h" namespace location { namespace nearby { namespace g3 { // See documentation in -// https://source.corp.google.com/piper///depot/google3/platform_v2/api/atomic_boolean.h +// https://source.corp.google.com/piper///depot/google3/platform/api/atomic_boolean.h class AtomicBoolean : public api::AtomicBoolean { public: explicit AtomicBoolean(bool initial_value) : value_(initial_value) {} @@ -27,4 +27,4 @@ class AtomicBoolean : public api::AtomicBoolean { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_G3_ATOMIC_BOOLEAN_H_ +#endif // PLATFORM_IMPL_G3_ATOMIC_BOOLEAN_H_ diff --git a/cpp/platform_v2/impl/g3/atomic_reference.h b/cpp/platform/impl/g3/atomic_reference.h similarity index 72% rename from cpp/platform_v2/impl/g3/atomic_reference.h rename to cpp/platform/impl/g3/atomic_reference.h index 2b33860f..c0b41137 100644 --- a/cpp/platform_v2/impl/g3/atomic_reference.h +++ b/cpp/platform/impl/g3/atomic_reference.h @@ -1,10 +1,10 @@ -#ifndef PLATFORM_V2_IMPL_G3_ATOMIC_REFERENCE_H_ -#define PLATFORM_V2_IMPL_G3_ATOMIC_REFERENCE_H_ +#ifndef PLATFORM_IMPL_G3_ATOMIC_REFERENCE_H_ +#define PLATFORM_IMPL_G3_ATOMIC_REFERENCE_H_ #include #include -#include "platform_v2/api/atomic_reference.h" +#include "platform/api/atomic_reference.h" namespace location { namespace nearby { @@ -30,4 +30,4 @@ class AtomicUint32 : public api::AtomicUint32 { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_G3_ATOMIC_REFERENCE_H_ +#endif // PLATFORM_IMPL_G3_ATOMIC_REFERENCE_H_ diff --git a/cpp/platform/impl/g3/atomic_reference_impl.h b/cpp/platform/impl/g3/atomic_reference_impl.h deleted file mode 100644 index b5f94c60..00000000 --- a/cpp/platform/impl/g3/atomic_reference_impl.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef PLATFORM_IMPL_G3_ATOMIC_REFERENCE_IMPL_H_ -#define PLATFORM_IMPL_G3_ATOMIC_REFERENCE_IMPL_H_ - -#include "platform/api/atomic_reference.h" -#include "platform/ptr.h" -#include "absl/base/integral_types.h" -#include "absl/synchronization/mutex.h" -#include "absl/types/any.h" - -namespace location { -namespace nearby { -namespace platform { - -// Provide implementation for absl::any. -class AtomicReferenceImpl : public AtomicReference { - public: - explicit AtomicReferenceImpl(absl::any initial_value) - : value_(std::move(initial_value)) {} - ~AtomicReferenceImpl() override = default; - - absl::any get() override { - absl::MutexLock lock(&mutex_); - return value_; - } - void set(absl::any value) override { - absl::MutexLock lock(&mutex_); - value_ = std::move(value); - } - - private: - absl::Mutex mutex_; - absl::any value_; -}; - -} // namespace platform -} // namespace nearby -} // namespace location - -#endif // PLATFORM_IMPL_G3_ATOMIC_REFERENCE_IMPL_H_ diff --git a/cpp/platform_v2/impl/g3/ble.cc b/cpp/platform/impl/g3/ble.cc similarity index 98% rename from cpp/platform_v2/impl/g3/ble.cc rename to cpp/platform/impl/g3/ble.cc index 316d64fc..646cdf20 100644 --- a/cpp/platform_v2/impl/g3/ble.cc +++ b/cpp/platform/impl/g3/ble.cc @@ -1,12 +1,12 @@ -#include "platform_v2/impl/g3/ble.h" +#include "platform/impl/g3/ble.h" #include #include #include -#include "platform_v2/api/ble.h" -#include "platform_v2/base/logging.h" -#include "platform_v2/base/medium_environment.h" +#include "platform/api/ble.h" +#include "platform/base/logging.h" +#include "platform/base/medium_environment.h" #include "absl/synchronization/mutex.h" namespace location { diff --git a/cpp/platform_v2/impl/g3/ble.h b/cpp/platform/impl/g3/ble.h similarity index 94% rename from cpp/platform_v2/impl/g3/ble.h rename to cpp/platform/impl/g3/ble.h index 9822200d..fb32f1d0 100644 --- a/cpp/platform_v2/impl/g3/ble.h +++ b/cpp/platform/impl/g3/ble.h @@ -1,17 +1,17 @@ -#ifndef PLATFORM_V2_IMPL_G3_BLE_H_ -#define PLATFORM_V2_IMPL_G3_BLE_H_ +#ifndef PLATFORM_IMPL_G3_BLE_H_ +#define PLATFORM_IMPL_G3_BLE_H_ #include #include -#include "platform_v2/api/ble.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/input_stream.h" -#include "platform_v2/base/output_stream.h" -#include "platform_v2/impl/g3/bluetooth_adapter.h" -#include "platform_v2/impl/g3/bluetooth_classic.h" -#include "platform_v2/impl/g3/multi_thread_executor.h" -#include "platform_v2/impl/g3/pipe.h" +#include "platform/api/ble.h" +#include "platform/base/byte_array.h" +#include "platform/base/input_stream.h" +#include "platform/base/output_stream.h" +#include "platform/impl/g3/bluetooth_adapter.h" +#include "platform/impl/g3/bluetooth_classic.h" +#include "platform/impl/g3/multi_thread_executor.h" +#include "platform/impl/g3/pipe.h" #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "absl/strings/escaping.h" @@ -212,4 +212,4 @@ class BleMedium : public api::BleMedium { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_G3_BLE_H_ +#endif // PLATFORM_IMPL_G3_BLE_H_ diff --git a/cpp/platform_v2/impl/g3/bluetooth_adapter.cc b/cpp/platform/impl/g3/bluetooth_adapter.cc similarity index 94% rename from cpp/platform_v2/impl/g3/bluetooth_adapter.cc rename to cpp/platform/impl/g3/bluetooth_adapter.cc index 877747ee..16b4b0a7 100644 --- a/cpp/platform_v2/impl/g3/bluetooth_adapter.cc +++ b/cpp/platform/impl/g3/bluetooth_adapter.cc @@ -1,10 +1,10 @@ -#include "platform_v2/impl/g3/bluetooth_adapter.h" +#include "platform/impl/g3/bluetooth_adapter.h" #include -#include "platform_v2/base/medium_environment.h" -#include "platform_v2/base/prng.h" -#include "platform_v2/impl/g3/bluetooth_classic.h" +#include "platform/base/medium_environment.h" +#include "platform/base/prng.h" +#include "platform/impl/g3/bluetooth_classic.h" namespace location { namespace nearby { diff --git a/cpp/platform_v2/impl/g3/bluetooth_adapter.h b/cpp/platform/impl/g3/bluetooth_adapter.h similarity index 92% rename from cpp/platform_v2/impl/g3/bluetooth_adapter.h rename to cpp/platform/impl/g3/bluetooth_adapter.h index 71220a9a..cf3bd324 100644 --- a/cpp/platform_v2/impl/g3/bluetooth_adapter.h +++ b/cpp/platform/impl/g3/bluetooth_adapter.h @@ -1,12 +1,12 @@ -#ifndef PLATFORM_V2_IMPL_G3_BLUETOOTH_ADAPTER_H_ -#define PLATFORM_V2_IMPL_G3_BLUETOOTH_ADAPTER_H_ +#ifndef PLATFORM_IMPL_G3_BLUETOOTH_ADAPTER_H_ +#define PLATFORM_IMPL_G3_BLUETOOTH_ADAPTER_H_ #include -#include "platform_v2/api/ble.h" -#include "platform_v2/api/bluetooth_adapter.h" -#include "platform_v2/api/bluetooth_classic.h" -#include "platform_v2/impl/g3/single_thread_executor.h" +#include "platform/api/ble.h" +#include "platform/api/bluetooth_adapter.h" +#include "platform/api/bluetooth_classic.h" +#include "platform/impl/g3/single_thread_executor.h" #include "absl/base/thread_annotations.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" @@ -125,4 +125,4 @@ class BluetoothAdapter : public api::BluetoothAdapter { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_G3_BLUETOOTH_ADAPTER_H_ +#endif // PLATFORM_IMPL_G3_BLUETOOTH_ADAPTER_H_ diff --git a/cpp/platform_v2/impl/g3/bluetooth_classic.cc b/cpp/platform/impl/g3/bluetooth_classic.cc similarity index 96% rename from cpp/platform_v2/impl/g3/bluetooth_classic.cc rename to cpp/platform/impl/g3/bluetooth_classic.cc index 36403954..4f25b74e 100644 --- a/cpp/platform_v2/impl/g3/bluetooth_classic.cc +++ b/cpp/platform/impl/g3/bluetooth_classic.cc @@ -1,12 +1,12 @@ -#include "platform_v2/impl/g3/bluetooth_classic.h" +#include "platform/impl/g3/bluetooth_classic.h" #include #include -#include "platform_v2/api/bluetooth_classic.h" -#include "platform_v2/base/logging.h" -#include "platform_v2/base/medium_environment.h" -#include "platform_v2/impl/g3/bluetooth_adapter.h" +#include "platform/api/bluetooth_classic.h" +#include "platform/base/logging.h" +#include "platform/base/medium_environment.h" +#include "platform/impl/g3/bluetooth_adapter.h" #include "absl/synchronization/mutex.h" namespace location { diff --git a/cpp/platform_v2/impl/g3/bluetooth_classic.h b/cpp/platform/impl/g3/bluetooth_classic.h similarity index 94% rename from cpp/platform_v2/impl/g3/bluetooth_classic.h rename to cpp/platform/impl/g3/bluetooth_classic.h index 0aa92c53..30cc2b53 100644 --- a/cpp/platform_v2/impl/g3/bluetooth_classic.h +++ b/cpp/platform/impl/g3/bluetooth_classic.h @@ -1,17 +1,17 @@ -#ifndef PLATFORM_V2_IMPL_G3_BLUETOOTH_CLASSIC_H_ -#define PLATFORM_V2_IMPL_G3_BLUETOOTH_CLASSIC_H_ +#ifndef PLATFORM_IMPL_G3_BLUETOOTH_CLASSIC_H_ +#define PLATFORM_IMPL_G3_BLUETOOTH_CLASSIC_H_ #include #include -#include "platform_v2/api/bluetooth_classic.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/exception.h" -#include "platform_v2/base/input_stream.h" -#include "platform_v2/base/listeners.h" -#include "platform_v2/base/output_stream.h" -#include "platform_v2/impl/g3/bluetooth_adapter.h" -#include "platform_v2/impl/g3/pipe.h" +#include "platform/api/bluetooth_classic.h" +#include "platform/base/byte_array.h" +#include "platform/base/exception.h" +#include "platform/base/input_stream.h" +#include "platform/base/listeners.h" +#include "platform/base/output_stream.h" +#include "platform/impl/g3/bluetooth_adapter.h" +#include "platform/impl/g3/pipe.h" #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "absl/synchronization/mutex.h" @@ -221,4 +221,4 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_G3_BLUETOOTH_CLASSIC_H_ +#endif // PLATFORM_IMPL_G3_BLUETOOTH_CLASSIC_H_ diff --git a/cpp/platform_v2/impl/g3/condition_variable.h b/cpp/platform/impl/g3/condition_variable.h similarity index 71% rename from cpp/platform_v2/impl/g3/condition_variable.h rename to cpp/platform/impl/g3/condition_variable.h index 4fc85689..e6205bed 100644 --- a/cpp/platform_v2/impl/g3/condition_variable.h +++ b/cpp/platform/impl/g3/condition_variable.h @@ -1,9 +1,9 @@ -#ifndef PLATFORM_V2_IMPL_G3_CONDITION_VARIABLE_H_ -#define PLATFORM_V2_IMPL_G3_CONDITION_VARIABLE_H_ +#ifndef PLATFORM_IMPL_G3_CONDITION_VARIABLE_H_ +#define PLATFORM_IMPL_G3_CONDITION_VARIABLE_H_ -#include "platform_v2/api/condition_variable.h" -#include "platform_v2/base/exception.h" -#include "platform_v2/impl/g3/mutex.h" +#include "platform/api/condition_variable.h" +#include "platform/base/exception.h" +#include "platform/impl/g3/mutex.h" #include "absl/synchronization/mutex.h" namespace location { @@ -34,4 +34,4 @@ class ConditionVariable : public api::ConditionVariable { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_G3_CONDITION_VARIABLE_H_ +#endif // PLATFORM_IMPL_G3_CONDITION_VARIABLE_H_ diff --git a/cpp/platform_v2/impl/g3/count_down_latch.h b/cpp/platform/impl/g3/count_down_latch.h similarity index 89% rename from cpp/platform_v2/impl/g3/count_down_latch.h rename to cpp/platform/impl/g3/count_down_latch.h index d5b423ab..ea61ee98 100644 --- a/cpp/platform_v2/impl/g3/count_down_latch.h +++ b/cpp/platform/impl/g3/count_down_latch.h @@ -1,7 +1,7 @@ -#ifndef PLATFORM_V2_IMPL_G3_COUNT_DOWN_LATCH_H_ -#define PLATFORM_V2_IMPL_G3_COUNT_DOWN_LATCH_H_ +#ifndef PLATFORM_IMPL_G3_COUNT_DOWN_LATCH_H_ +#define PLATFORM_IMPL_G3_COUNT_DOWN_LATCH_H_ -#include "platform_v2/api/count_down_latch.h" +#include "platform/api/count_down_latch.h" #include "absl/base/thread_annotations.h" #include "absl/synchronization/mutex.h" #include "absl/time/clock.h" @@ -56,4 +56,4 @@ class CountDownLatch final : public api::CountDownLatch { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_G3_COUNT_DOWN_LATCH_H_ +#endif // PLATFORM_IMPL_G3_COUNT_DOWN_LATCH_H_ diff --git a/cpp/platform_v2/impl/g3/crypto.cc b/cpp/platform/impl/g3/crypto.cc similarity index 91% rename from cpp/platform_v2/impl/g3/crypto.cc rename to cpp/platform/impl/g3/crypto.cc index 52912f13..e4ba2ccd 100644 --- a/cpp/platform_v2/impl/g3/crypto.cc +++ b/cpp/platform/impl/g3/crypto.cc @@ -1,9 +1,9 @@ -#include "platform_v2/api/crypto.h" +#include "platform/api/crypto.h" #include #include -#include "platform_v2/base/byte_array.h" +#include "platform/base/byte_array.h" #include "absl/strings/string_view.h" #include "openssl/digest.h" diff --git a/cpp/platform_v2/impl/g3/log_message.cc b/cpp/platform/impl/g3/log_message.cc similarity index 96% rename from cpp/platform_v2/impl/g3/log_message.cc rename to cpp/platform/impl/g3/log_message.cc index a9dce4f3..ebd0210d 100644 --- a/cpp/platform_v2/impl/g3/log_message.cc +++ b/cpp/platform/impl/g3/log_message.cc @@ -1,4 +1,4 @@ -#include "platform_v2/impl/g3/log_message.h" +#include "platform/impl/g3/log_message.h" #include diff --git a/cpp/platform_v2/impl/g3/log_message.h b/cpp/platform/impl/g3/log_message.h similarity index 72% rename from cpp/platform_v2/impl/g3/log_message.h rename to cpp/platform/impl/g3/log_message.h index 25e1fe89..285e0ded 100644 --- a/cpp/platform_v2/impl/g3/log_message.h +++ b/cpp/platform/impl/g3/log_message.h @@ -1,15 +1,15 @@ -#ifndef PLATFORM_V2_IMPL_G3_LOG_MESSAGE_H_ -#define PLATFORM_V2_IMPL_G3_LOG_MESSAGE_H_ +#ifndef PLATFORM_IMPL_G3_LOG_MESSAGE_H_ +#define PLATFORM_IMPL_G3_LOG_MESSAGE_H_ #include "base/logging.h" -#include "platform_v2/api/log_message.h" +#include "platform/api/log_message.h" namespace location { namespace nearby { namespace g3 { // See documentation in -// https://source.corp.google.com/piper///depot/google3/platform_v2/api/log_message.h +// https://source.corp.google.com/piper///depot/google3/platform/api/log_message.h class LogMessage : public api::LogMessage { public: LogMessage(const char* file, int line, Severity severity); @@ -27,4 +27,4 @@ class LogMessage : public api::LogMessage { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_G3_LOG_MESSAGE_H_ +#endif // PLATFORM_IMPL_G3_LOG_MESSAGE_H_ diff --git a/cpp/platform_v2/impl/g3/multi_thread_executor.h b/cpp/platform/impl/g3/multi_thread_executor.h similarity index 83% rename from cpp/platform_v2/impl/g3/multi_thread_executor.h rename to cpp/platform/impl/g3/multi_thread_executor.h index c2672db1..63ba0165 100644 --- a/cpp/platform_v2/impl/g3/multi_thread_executor.h +++ b/cpp/platform/impl/g3/multi_thread_executor.h @@ -1,10 +1,10 @@ -#ifndef PLATFORM_V2_IMPL_G3_MULTI_THREAD_EXECUTOR_H_ -#define PLATFORM_V2_IMPL_G3_MULTI_THREAD_EXECUTOR_H_ +#ifndef PLATFORM_IMPL_G3_MULTI_THREAD_EXECUTOR_H_ +#define PLATFORM_IMPL_G3_MULTI_THREAD_EXECUTOR_H_ #include -#include "platform_v2/api/submittable_executor.h" -#include "platform_v2/impl/g3/count_down_latch.h" +#include "platform/api/submittable_executor.h" +#include "platform/impl/g3/count_down_latch.h" #include "absl/time/clock.h" #include "thread/threadpool.h" @@ -56,4 +56,4 @@ class MultiThreadExecutor : public api::SubmittableExecutor { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_G3_MULTI_THREAD_EXECUTOR_H_ +#endif // PLATFORM_IMPL_G3_MULTI_THREAD_EXECUTOR_H_ diff --git a/cpp/platform_v2/impl/g3/mutex.h b/cpp/platform/impl/g3/mutex.h similarity index 84% rename from cpp/platform_v2/impl/g3/mutex.h rename to cpp/platform/impl/g3/mutex.h index a70a2f2a..776dc15d 100644 --- a/cpp/platform_v2/impl/g3/mutex.h +++ b/cpp/platform/impl/g3/mutex.h @@ -1,8 +1,8 @@ -#ifndef PLATFORM_V2_IMPL_G3_MUTEX_H_ -#define PLATFORM_V2_IMPL_G3_MUTEX_H_ +#ifndef PLATFORM_IMPL_G3_MUTEX_H_ +#define PLATFORM_IMPL_G3_MUTEX_H_ -#include "platform_v2/api/mutex.h" -#include "platform_v2/impl/shared/posix_mutex.h" +#include "platform/api/mutex.h" +#include "platform/impl/shared/posix_mutex.h" #include "absl/synchronization/mutex.h" namespace location { @@ -44,4 +44,4 @@ class ABSL_LOCKABLE RecursiveMutex : public posix::Mutex { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_G3_MUTEX_H_ +#endif // PLATFORM_IMPL_G3_MUTEX_H_ diff --git a/cpp/platform_v2/impl/g3/pipe.h b/cpp/platform/impl/g3/pipe.h similarity index 66% rename from cpp/platform_v2/impl/g3/pipe.h rename to cpp/platform/impl/g3/pipe.h index 9c1c1a8b..882bfb8e 100644 --- a/cpp/platform_v2/impl/g3/pipe.h +++ b/cpp/platform/impl/g3/pipe.h @@ -1,11 +1,11 @@ -#ifndef PLATFORM_V2_IMPL_G3_PIPE_H_ -#define PLATFORM_V2_IMPL_G3_PIPE_H_ +#ifndef PLATFORM_IMPL_G3_PIPE_H_ +#define PLATFORM_IMPL_G3_PIPE_H_ #include -#include "platform_v2/base/base_pipe.h" -#include "platform_v2/impl/g3/condition_variable.h" -#include "platform_v2/impl/g3/mutex.h" +#include "platform/base/base_pipe.h" +#include "platform/impl/g3/condition_variable.h" +#include "platform/impl/g3/mutex.h" namespace location { namespace nearby { @@ -27,4 +27,4 @@ class Pipe : public BasePipe { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_G3_PIPE_H_ +#endif // PLATFORM_IMPL_G3_PIPE_H_ diff --git a/cpp/platform/impl/g3/platform.cc b/cpp/platform/impl/g3/platform.cc index abd700f6..e6ea1299 100644 --- a/cpp/platform/impl/g3/platform.cc +++ b/cpp/platform/impl/g3/platform.cc @@ -5,146 +5,155 @@ #include "platform/api/atomic_boolean.h" #include "platform/api/atomic_reference.h" -#include "platform/api/ble.h" #include "platform/api/ble_v2.h" #include "platform/api/bluetooth_adapter.h" #include "platform/api/bluetooth_classic.h" #include "platform/api/condition_variable.h" #include "platform/api/count_down_latch.h" -#include "platform/api/hash_utils.h" -#include "platform/api/lock.h" +#include "platform/api/log_message.h" +#include "platform/api/mutex.h" #include "platform/api/scheduled_executor.h" #include "platform/api/server_sync.h" -#include "platform/api/settable_future.h" #include "platform/api/submittable_executor.h" -#include "platform/api/system_clock.h" -#include "platform/api/thread_utils.h" #include "platform/api/webrtc.h" #include "platform/api/wifi.h" -#include "platform/impl/g3/atomic_reference_impl.h" -#include "platform/impl/g3/settable_future_impl.h" -#include "platform/impl/g3/system_clock_impl.h" -#include "platform/impl/shared/atomic_boolean_impl.h" -#include "platform/impl/shared/file_impl.h" -#include "platform/impl/shared/posix_condition_variable.h" -#include "platform/impl/shared/posix_lock.h" -#include "platform/port/string.h" -#include "platform/ptr.h" +#include "platform/base/medium_environment.h" +#include "platform/impl/g3/atomic_boolean.h" +#include "platform/impl/g3/atomic_reference.h" +#include "platform/impl/g3/ble.h" +#include "platform/impl/g3/bluetooth_adapter.h" +#include "platform/impl/g3/bluetooth_classic.h" +#include "platform/impl/g3/condition_variable.h" +#include "platform/impl/g3/count_down_latch.h" +#include "platform/impl/g3/log_message.h" +#include "platform/impl/g3/multi_thread_executor.h" +#include "platform/impl/g3/mutex.h" +#include "platform/impl/g3/scheduled_executor.h" +#include "platform/impl/g3/single_thread_executor.h" +#include "platform/impl/g3/webrtc.h" +#include "platform/impl/g3/wifi_lan.h" +#include "platform/impl/shared/file.h" #include "absl/base/integral_types.h" -#include "absl/synchronization/mutex.h" +#include "absl/memory/memory.h" +#include "absl/strings/str_cat.h" #include "absl/time/time.h" namespace location { namespace nearby { -namespace platform { +namespace api { namespace { -std::string getPayloadPath(std::int64_t payload_id) { - return "/tmp/" + std::to_string(payload_id); +std::string GetPayloadPath(PayloadId payload_id) { + return absl::StrCat("/tmp/", payload_id); } } // namespace -Ptr ImplementationPlatform::createSingleThreadExecutor() { - return Ptr(/*new SingleThreadExecutorImpl()*/); +int GetCurrentTid() { + const LiveThread* my = Thread_GetMyLiveThread(); + return LiveThread_Pthread_TID(my); } -Ptr ImplementationPlatform::createMultiThreadExecutor( - int max_concurrency) { - return Ptr(/*new MultiThreadExecutorImpl()*/); +std::unique_ptr +ImplementationPlatform::CreateSingleThreadExecutor() { + return absl::make_unique(); } -Ptr ImplementationPlatform::createScheduledExecutor() { - return Ptr(/*new ScheduledExecutorImpl()*/); +std::unique_ptr +ImplementationPlatform::CreateMultiThreadExecutor(int max_concurrency) { + return absl::make_unique(max_concurrency); } -Ptr> -ImplementationPlatform::createAtomicReferenceAny(absl::any initial_value) { - return Ptr>( - new AtomicReferenceImpl(initial_value)); +std::unique_ptr +ImplementationPlatform::CreateScheduledExecutor() { + return absl::make_unique(); } -Ptr> -ImplementationPlatform::createSettableFutureAny() { - return Ptr>(new SettableFutureImpl{}); +std::unique_ptr +ImplementationPlatform::CreateAtomicUint32(std::uint32_t value) { + return absl::make_unique(value); } -Ptr ImplementationPlatform::createBluetoothAdapter() { - return Ptr{}; +std::unique_ptr +ImplementationPlatform::CreateBluetoothAdapter() { + return absl::make_unique(); } -Ptr ImplementationPlatform::createWifiMedium() { - return Ptr(); -} - -Ptr ImplementationPlatform::createCountDownLatch( +std::unique_ptr ImplementationPlatform::CreateCountDownLatch( std::int32_t count) { - return Ptr(/*new CountDownLatchImpl(count)*/); + return absl::make_unique(count); } -Ptr ImplementationPlatform::createThreadUtils() { - return Ptr(/*new ThreadUtilsImpl()*/); -} - -Ptr ImplementationPlatform::createSystemClock() { - return Ptr(new SystemClockImpl()); -} - -Ptr ImplementationPlatform::createAtomicBoolean( +std::unique_ptr ImplementationPlatform::CreateAtomicBoolean( bool initial_value) { - return Ptr(new AtomicBooleanImpl(initial_value)); + return absl::make_unique(initial_value); } -Ptr ImplementationPlatform::createInputFile( - std::int64_t payload_id, std::int64_t total_size) { - return MakePtr(new InputFileImpl(getPayloadPath(payload_id), total_size)); +std::unique_ptr ImplementationPlatform::CreateInputFile( + PayloadId payload_id, std::int64_t total_size) { + return absl::make_unique(GetPayloadPath(payload_id), + total_size); } -Ptr ImplementationPlatform::createOutputFile( - std::int64_t payload_id) { - return MakePtr(new OutputFileImpl(getPayloadPath(payload_id))); +std::unique_ptr ImplementationPlatform::CreateOutputFile( + PayloadId payload_id) { + return absl::make_unique(GetPayloadPath(payload_id)); } -Ptr -ImplementationPlatform::createBluetoothClassicMedium() { - return Ptr(); +std::unique_ptr ImplementationPlatform::CreateLogMessage( + const char* file, int line, LogMessage::Severity severity) { + return absl::make_unique(file, line, severity); } -Ptr ImplementationPlatform::createBLEMedium() { - return Ptr(); +std::unique_ptr +ImplementationPlatform::CreateBluetoothClassicMedium( + api::BluetoothAdapter& adapter) { + return absl::make_unique(adapter); } -Ptr ImplementationPlatform::createBLEMediumV2() { - return Ptr(); +std::unique_ptr ImplementationPlatform::CreateBleMedium( + api::BluetoothAdapter& adapter) { + return absl::make_unique(adapter); } -Ptr ImplementationPlatform::createServerSyncMedium() { - return Ptr(/*new ServerSyncMediumImpl()*/); +std::unique_ptr ImplementationPlatform::CreateBleV2Medium( + api::BluetoothAdapter& adapter) { + return std::unique_ptr(); } -Ptr -ImplementationPlatform::createWebRtcSignalingMessenger( - const std::string& self_id) { - return Ptr(/*new FCMSignalingMessenger()*/); +std::unique_ptr +ImplementationPlatform::CreateServerSyncMedium() { + return std::unique_ptr(/*new ServerSyncMediumImpl()*/); } -Ptr ImplementationPlatform::createLock() { - return Ptr(new PosixLock()); +std::unique_ptr ImplementationPlatform::CreateWifiMedium() { + return std::unique_ptr(); } -Ptr ImplementationPlatform::createConditionVariable( - Ptr lock) { - return Ptr(new PosixConditionVariable(lock)); +std::unique_ptr ImplementationPlatform::CreateWifiLanMedium() { + return absl::make_unique(); } -Ptr ImplementationPlatform::createHashUtils() { - return Ptr(/*new HashUtilsImpl()*/); +std::unique_ptr ImplementationPlatform::CreateWebRtcMedium() { + if (MediumEnvironment::Instance().GetEnvironmentConfig().webrtc_enabled) { + return absl::make_unique(); + } else { + return nullptr; + } } -std::string ImplementationPlatform::getDeviceId() { - // TODO(alexchau): Get deviceId from base - return "google3"; +std::unique_ptr ImplementationPlatform::CreateMutex(Mutex::Mode mode) { + if (mode == Mutex::Mode::kRecursive) + return absl::make_unique(); + else + return absl::make_unique(mode == Mutex::Mode::kRegular); } -} // namespace platform +std::unique_ptr +ImplementationPlatform::CreateConditionVariable(Mutex* mutex) { + return std::unique_ptr( + new g3::ConditionVariable(static_cast(mutex))); +} + +} // namespace api } // namespace nearby } // namespace location diff --git a/cpp/platform_v2/impl/g3/scheduled_executor.cc b/cpp/platform/impl/g3/scheduled_executor.cc similarity index 91% rename from cpp/platform_v2/impl/g3/scheduled_executor.cc rename to cpp/platform/impl/g3/scheduled_executor.cc index 1f8a3290..58dc7305 100644 --- a/cpp/platform_v2/impl/g3/scheduled_executor.cc +++ b/cpp/platform/impl/g3/scheduled_executor.cc @@ -1,10 +1,10 @@ -#include "platform_v2/impl/g3/scheduled_executor.h" +#include "platform/impl/g3/scheduled_executor.h" #include #include -#include "platform_v2/api/cancelable.h" -#include "platform_v2/base/runnable.h" +#include "platform/api/cancelable.h" +#include "platform/base/runnable.h" #include "absl/time/clock.h" namespace location { diff --git a/cpp/platform_v2/impl/g3/scheduled_executor.h b/cpp/platform/impl/g3/scheduled_executor.h similarity index 73% rename from cpp/platform_v2/impl/g3/scheduled_executor.h rename to cpp/platform/impl/g3/scheduled_executor.h index 9ffea951..c5e08605 100644 --- a/cpp/platform_v2/impl/g3/scheduled_executor.h +++ b/cpp/platform/impl/g3/scheduled_executor.h @@ -1,13 +1,13 @@ -#ifndef PLATFORM_V2_IMPL_G3_SCHEDULED_EXECUTOR_H_ -#define PLATFORM_V2_IMPL_G3_SCHEDULED_EXECUTOR_H_ +#ifndef PLATFORM_IMPL_G3_SCHEDULED_EXECUTOR_H_ +#define PLATFORM_IMPL_G3_SCHEDULED_EXECUTOR_H_ #include #include -#include "platform_v2/api/cancelable.h" -#include "platform_v2/api/scheduled_executor.h" -#include "platform_v2/base/runnable.h" -#include "platform_v2/impl/g3/single_thread_executor.h" +#include "platform/api/cancelable.h" +#include "platform/api/scheduled_executor.h" +#include "platform/base/runnable.h" +#include "platform/impl/g3/single_thread_executor.h" #include "absl/time/clock.h" #include "thread/threadpool.h" @@ -42,4 +42,4 @@ class ScheduledExecutor final : public api::ScheduledExecutor { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_G3_SCHEDULED_EXECUTOR_H_ +#endif // PLATFORM_IMPL_G3_SCHEDULED_EXECUTOR_H_ diff --git a/cpp/platform/impl/g3/settable_future_impl.h b/cpp/platform/impl/g3/settable_future_impl.h deleted file mode 100644 index 36e5aebf..00000000 --- a/cpp/platform/impl/g3/settable_future_impl.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef PLATFORM_IMPL_G3_SETTABLE_FUTURE_IMPL_H_ -#define PLATFORM_IMPL_G3_SETTABLE_FUTURE_IMPL_H_ - -#include - -#include "platform/api/platform.h" -#include "platform/api/settable_future.h" -#include "absl/synchronization/mutex.h" -#include "absl/time/clock.h" -#include "absl/types/any.h" - -namespace location { -namespace nearby { -namespace platform { - -class SettableFutureImpl : public SettableFuture { - public: - explicit SettableFutureImpl() = default; - ~SettableFutureImpl() override = default; - - bool set(absl::any value) override { - absl::MutexLock lock(&mutex_); - if (!done_) { - value_ = std::move(value); - done_ = true; - exception_ = {Exception::kSuccess}; - completed_.SignalAll(); - } - return true; - } - - bool setException(Exception exception) override { - absl::MutexLock lock(&mutex_); - return SetExceptionLocked(exception); - } - - void addListener(Ptr runnable, Executor* executor) override {} - - ExceptionOr get() override { - absl::MutexLock lock(&mutex_); - while (!done_) { - completed_.Wait(&mutex_); - } - return exception_.value != Exception::kSuccess - ? ExceptionOr{exception_.value} - : ExceptionOr{value_}; - } - - ExceptionOr get(std::int64_t timeout_ms) override { - absl::MutexLock lock(&mutex_); - absl::Duration timeout = absl::Milliseconds(timeout_ms); - while (!done_) { - absl::Time start_time = absl::Now(); - if (completed_.WaitWithTimeout(&mutex_, timeout)) { - SetExceptionLocked({Exception::kTimeout}); - break; - } - absl::Duration spent = absl::Now() - start_time; - if (spent < timeout) { - timeout -= spent; - } else if (!done_) { - SetExceptionLocked({Exception::kTimeout}); - break; - } - } - return exception_.value != Exception::kSuccess - ? ExceptionOr{exception_.value} - : ExceptionOr{value_}; - } - - private: - bool SetExceptionLocked(Exception exception) { - if (!done_) { - exception_ = exception.value != Exception::kSuccess - ? exception - : Exception{Exception::kFailed}; - done_ = true; - completed_.SignalAll(); - } - return true; - } - - absl::Mutex mutex_; - absl::CondVar completed_; - bool done_{false}; - absl::any value_; - Exception exception_{Exception::kFailed}; -}; - -} // namespace platform -} // namespace nearby -} // namespace location - -#endif // PLATFORM_IMPL_G3_SETTABLE_FUTURE_IMPL_H_ diff --git a/cpp/platform_v2/impl/g3/single_thread_executor.h b/cpp/platform/impl/g3/single_thread_executor.h similarity index 63% rename from cpp/platform_v2/impl/g3/single_thread_executor.h rename to cpp/platform/impl/g3/single_thread_executor.h index 384206d7..7dc4cec1 100644 --- a/cpp/platform_v2/impl/g3/single_thread_executor.h +++ b/cpp/platform/impl/g3/single_thread_executor.h @@ -1,7 +1,7 @@ -#ifndef PLATFORM_V2_IMPL_G3_SINGLE_THREAD_EXECUTOR_H_ -#define PLATFORM_V2_IMPL_G3_SINGLE_THREAD_EXECUTOR_H_ +#ifndef PLATFORM_IMPL_G3_SINGLE_THREAD_EXECUTOR_H_ +#define PLATFORM_IMPL_G3_SINGLE_THREAD_EXECUTOR_H_ -#include "platform_v2/impl/g3/multi_thread_executor.h" +#include "platform/impl/g3/multi_thread_executor.h" namespace location { namespace nearby { @@ -19,4 +19,4 @@ class SingleThreadExecutor final : public MultiThreadExecutor { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_G3_SINGLE_THREAD_EXECUTOR_H_ +#endif // PLATFORM_IMPL_G3_SINGLE_THREAD_EXECUTOR_H_ diff --git a/cpp/platform_v2/impl/g3/system_clock.cc b/cpp/platform/impl/g3/system_clock.cc similarity index 78% rename from cpp/platform_v2/impl/g3/system_clock.cc rename to cpp/platform/impl/g3/system_clock.cc index 2f613dd7..d1b0f99b 100644 --- a/cpp/platform_v2/impl/g3/system_clock.cc +++ b/cpp/platform/impl/g3/system_clock.cc @@ -1,6 +1,6 @@ -#include "platform_v2/api/system_clock.h" +#include "platform/api/system_clock.h" -#include "platform_v2/base/exception.h" +#include "platform/base/exception.h" #include "absl/time/clock.h" namespace location { diff --git a/cpp/platform/impl/g3/system_clock_impl.h b/cpp/platform/impl/g3/system_clock_impl.h deleted file mode 100644 index 5f7d22ee..00000000 --- a/cpp/platform/impl/g3/system_clock_impl.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef PLATFORM_IMPL_G3_SYSTEM_CLOCK_IMPL_H_ -#define PLATFORM_IMPL_G3_SYSTEM_CLOCK_IMPL_H_ - -#include - -#include "platform/api/system_clock.h" -#include "absl/time/clock.h" -#include "absl/time/time.h" - -namespace location { -namespace nearby { - -class SystemClockImpl : public SystemClock { - public: - std::int64_t elapsedRealtime() override { - return absl::ToUnixMillis(absl::Now()); - } -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_IMPL_G3_SYSTEM_CLOCK_IMPL_H_ diff --git a/cpp/platform_v2/impl/g3/webrtc.cc b/cpp/platform/impl/g3/webrtc.cc similarity index 79% rename from cpp/platform_v2/impl/g3/webrtc.cc rename to cpp/platform/impl/g3/webrtc.cc index 7dc16a2f..bd6d2ac1 100644 --- a/cpp/platform_v2/impl/g3/webrtc.cc +++ b/cpp/platform/impl/g3/webrtc.cc @@ -1,16 +1,17 @@ -#include "platform_v2/impl/g3/webrtc.h" +#include "platform/impl/g3/webrtc.h" #include -#include "platform_v2/base/medium_environment.h" +#include "platform/base/medium_environment.h" #include "webrtc/api/task_queue/default_task_queue_factory.h" namespace location { namespace nearby { namespace g3 { -WebRtcSignalingMessenger::WebRtcSignalingMessenger(absl::string_view self_id) - : self_id_(self_id) {} +WebRtcSignalingMessenger::WebRtcSignalingMessenger( + absl::string_view self_id, const connections::LocationHint& location_hint) + : self_id_(self_id), location_hint_(location_hint) {} bool WebRtcSignalingMessenger::SendMessage(absl::string_view peer_id, const ByteArray& message) { @@ -57,8 +58,9 @@ void WebRtcMedium::CreatePeerConnection( } std::unique_ptr -WebRtcMedium::GetSignalingMessenger(absl::string_view self_id) { - return std::make_unique(self_id); +WebRtcMedium::GetSignalingMessenger( + absl::string_view self_id, const connections::LocationHint& location_hint) { + return std::make_unique(self_id, location_hint); } } // namespace g3 diff --git a/cpp/platform_v2/impl/g3/webrtc.h b/cpp/platform/impl/g3/webrtc.h similarity index 77% rename from cpp/platform_v2/impl/g3/webrtc.h rename to cpp/platform/impl/g3/webrtc.h index 12cb5a8d..b9a6c4ea 100644 --- a/cpp/platform_v2/impl/g3/webrtc.h +++ b/cpp/platform/impl/g3/webrtc.h @@ -1,9 +1,9 @@ -#ifndef PLATFORM_V2_IMPL_G3_WEBRTC_H_ -#define PLATFORM_V2_IMPL_G3_WEBRTC_H_ +#ifndef PLATFORM_IMPL_G3_WEBRTC_H_ +#define PLATFORM_IMPL_G3_WEBRTC_H_ #include -#include "platform_v2/api/webrtc.h" +#include "platform/api/webrtc.h" #include "absl/strings/string_view.h" #include "webrtc/api/peer_connection_interface.h" @@ -16,7 +16,9 @@ class WebRtcSignalingMessenger : public api::WebRtcSignalingMessenger { using OnSignalingMessageCallback = api::WebRtcSignalingMessenger::OnSignalingMessageCallback; - explicit WebRtcSignalingMessenger(absl::string_view self_id); + explicit WebRtcSignalingMessenger( + absl::string_view self_id, + const connections::LocationHint& location_hint); ~WebRtcSignalingMessenger() override = default; bool SendMessage(absl::string_view peer_id, @@ -26,6 +28,7 @@ class WebRtcSignalingMessenger : public api::WebRtcSignalingMessenger { private: absl::string_view self_id_; + connections::LocationHint location_hint_; }; class WebRtcMedium : public api::WebRtcMedium { @@ -42,7 +45,9 @@ class WebRtcMedium : public api::WebRtcMedium { // Returns a signaling messenger for sending WebRTC signaling messages. std::unique_ptr GetSignalingMessenger( - absl::string_view self_id) override; + absl::string_view self_id, + const connections::LocationHint& location_hint) override; + private: std::unique_ptr signaling_thread_; }; @@ -51,4 +56,4 @@ class WebRtcMedium : public api::WebRtcMedium { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_G3_WEBRTC_H_ +#endif // PLATFORM_IMPL_G3_WEBRTC_H_ diff --git a/cpp/platform_v2/impl/g3/wifi_lan.cc b/cpp/platform/impl/g3/wifi_lan.cc similarity index 95% rename from cpp/platform_v2/impl/g3/wifi_lan.cc rename to cpp/platform/impl/g3/wifi_lan.cc index 9afb97d5..988d9f40 100644 --- a/cpp/platform_v2/impl/g3/wifi_lan.cc +++ b/cpp/platform/impl/g3/wifi_lan.cc @@ -1,13 +1,13 @@ -#include "platform_v2/impl/g3/wifi_lan.h" +#include "platform/impl/g3/wifi_lan.h" #include #include #include -#include "platform_v2/api/wifi_lan.h" -#include "platform_v2/base/logging.h" -#include "platform_v2/base/medium_environment.h" -#include "platform_v2/base/prng.h" +#include "platform/api/wifi_lan.h" +#include "platform/base/logging.h" +#include "platform/base/medium_environment.h" +#include "platform/base/prng.h" #include "absl/synchronization/mutex.h" namespace location { @@ -191,12 +191,14 @@ WifiLanMedium::~WifiLanMedium() { } bool WifiLanMedium::StartAdvertising(const std::string& service_id, - const std::string& service_info_name) { + const std::string& service_info_name, + const std::string& endpoint_info_name) { NEARBY_LOG(INFO, "G3 WifiLan StartAdvertising: service_id=%s, service_info_name=%s", service_id.c_str(), service_info_name.c_str()); auto& env = MediumEnvironment::Instance(); - service_.SetName(service_info_name); + service_.SetServiceName(service_info_name); + service_.SetTxtRecord("n", endpoint_info_name); env.UpdateWifiLanMediumForAdvertising(*this, service_, service_id, true); absl::MutexLock lock(&mutex_); @@ -310,7 +312,7 @@ std::unique_ptr WifiLanMedium::Connect( NEARBY_LOG(INFO, "G3 WifiLan Connect: medium=%p, service=%p, service_info_name=%s, " "service_id=%s", - this, &service_, remote_service.GetName().c_str(), + this, &service_, remote_service.GetServiceName().c_str(), service_id.c_str()); // First, find an instance of remote medium, that exposed this service. auto* medium = static_cast(remote_service).GetMedium(); @@ -321,7 +323,7 @@ std::unique_ptr WifiLanMedium::Connect( NEARBY_LOG(INFO, "G3 WifiLan Connect [peer]: medium=%p, service=%p, " "service_info_name=%s, service_id=%s", - medium, &remote_service, remote_service.GetName().c_str(), + medium, &remote_service, remote_service.GetServiceName().c_str(), service_id.c_str()); // Then, find our server socket context in this medium. { diff --git a/cpp/platform_v2/impl/g3/wifi_lan.h b/cpp/platform/impl/g3/wifi_lan.h similarity index 88% rename from cpp/platform_v2/impl/g3/wifi_lan.h rename to cpp/platform/impl/g3/wifi_lan.h index c6aa8292..dfea6d62 100644 --- a/cpp/platform_v2/impl/g3/wifi_lan.h +++ b/cpp/platform/impl/g3/wifi_lan.h @@ -1,16 +1,16 @@ -#ifndef PLATFORM_V2_IMPL_G3_WIFI_LAN_H_ -#define PLATFORM_V2_IMPL_G3_WIFI_LAN_H_ +#ifndef PLATFORM_IMPL_G3_WIFI_LAN_H_ +#define PLATFORM_IMPL_G3_WIFI_LAN_H_ #include #include #include -#include "platform_v2/api/wifi_lan.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/input_stream.h" -#include "platform_v2/base/output_stream.h" -#include "platform_v2/impl/g3/multi_thread_executor.h" -#include "platform_v2/impl/g3/pipe.h" +#include "platform/api/wifi_lan.h" +#include "platform/base/byte_array.h" +#include "platform/base/input_stream.h" +#include "platform/base/output_stream.h" +#include "platform/impl/g3/multi_thread_executor.h" +#include "platform/impl/g3/pipe.h" #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "absl/synchronization/mutex.h" @@ -29,24 +29,40 @@ class WifiLanService : public api::WifiLanService { : service_info_name_(std::move(service_info_name)) {} ~WifiLanService() override = default; - void SetName(std::string service_info_name) { + std::string GetServiceName() const override { return service_info_name_; } + + void SetServiceName(std::string service_info_name) { service_info_name_ = std::move(service_info_name); } - std::string GetName() const override { return service_info_name_; } + + std::string GetTxtRecord(const std::string& txt_record_key) const override { + if (txt_records_.empty()) return {}; + auto record = txt_records_.find(txt_record_key); + if (record == txt_records_.end()) return {}; + return record->second; + } + + void SetTxtRecord(const std::string& txt_record_key, + const std::string& txt_record_value) { + txt_records_.emplace(txt_record_key, txt_record_value); + } + std::pair GetServiceAddress() const override { return std::make_pair(ip_address_, port_); } - void SetMedium(WifiLanMedium* medium) { medium_ = medium; } - WifiLanMedium* GetMedium() { return medium_; } - void SetServiceAddress(const std::string& ip_address, int port) { ip_address_ = ip_address; port_ = port; } + WifiLanMedium* GetMedium() { return medium_; } + + void SetMedium(WifiLanMedium* medium) { medium_ = medium; } + private: std::string service_info_name_; + absl::flat_hash_map txt_records_; WifiLanMedium* medium_ = nullptr; std::string ip_address_; int port_; @@ -166,7 +182,8 @@ class WifiLanMedium : public api::WifiLanMedium { ~WifiLanMedium() override; bool StartAdvertising(const std::string& service_id, - const std::string& service_info_name) override + const std::string& service_info_name, + const std::string& endpoint_info_name) override ABSL_LOCKS_EXCLUDED(mutex_); bool StopAdvertising(const std::string& service_id) override ABSL_LOCKS_EXCLUDED(mutex_); @@ -239,4 +256,4 @@ class WifiLanMedium : public api::WifiLanMedium { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_G3_WIFI_LAN_H_ +#endif // PLATFORM_IMPL_G3_WIFI_LAN_H_ diff --git a/cpp/platform/impl/ios/BUILD b/cpp/platform/impl/ios/BUILD index a75790f9..5dd6bdce 100644 --- a/cpp/platform/impl/ios/BUILD +++ b/cpp/platform/impl/ios/BUILD @@ -1,9 +1,56 @@ objc_library( - name = "ios", + name = "types", + srcs = [ + "log_message.mm", + "scheduled_executor.mm", + ], + hdrs = [ + "atomic_boolean.h", + "atomic_reference.h", + "condition_variable.h", + "count_down_latch.h", + "log_message.h", + "multi_thread_executor.h", + "mutex.h", + "scheduled_executor.h", + "single_thread_executor.h", + ], visibility = [ - "//googlemac/iPhone/Nearby/HelloSetup:__subpackages__", + "//platform/impl/ios:__pkg__", ], deps = [ - "//googlemac/iPhone/Shared/Nearby/Connections:Platform", + "//base", + "//platform/api:platform", + "//platform/api:types", + "//platform/base", + "//platform/base:util", + "//platform/impl/shared:posix_mutex", + "//absl/base:core_headers", + "//absl/synchronization", + "//absl/time", + "//thread", + ], +) + +objc_library( + name = "ios", + srcs = [ + "platform.mm", + ], + visibility = [ + "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", + "//core:__subpackages__", + "//platform:__subpackages__", + ], + deps = [ + ":types", + "//platform/api:comm", + "//platform/api:platform", + "//platform/api:types", + "//platform/impl/shared:file", + "//absl/base:core_headers", + "//absl/memory", + "//absl/strings", + "//absl/time", ], ) diff --git a/cpp/platform_v2/impl/ios/atomic_boolean.h b/cpp/platform/impl/ios/atomic_boolean.h similarity index 71% rename from cpp/platform_v2/impl/ios/atomic_boolean.h rename to cpp/platform/impl/ios/atomic_boolean.h index 37a1d1f1..5a14cb18 100644 --- a/cpp/platform_v2/impl/ios/atomic_boolean.h +++ b/cpp/platform/impl/ios/atomic_boolean.h @@ -1,9 +1,9 @@ -#ifndef PLATFORM_V2_IMPL_IOS_ATOMIC_BOOLEAN_H_ -#define PLATFORM_V2_IMPL_IOS_ATOMIC_BOOLEAN_H_ +#ifndef PLATFORM_IMPL_IOS_ATOMIC_BOOLEAN_H_ +#define PLATFORM_IMPL_IOS_ATOMIC_BOOLEAN_H_ #include -#include "platform_v2/api/atomic_boolean.h" +#include "platform/api/atomic_boolean.h" namespace location { namespace nearby { @@ -25,4 +25,4 @@ class AtomicBoolean : public api::AtomicBoolean { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_IOS_ATOMIC_BOOLEAN_H_ +#endif // PLATFORM_IMPL_IOS_ATOMIC_BOOLEAN_H_ diff --git a/cpp/platform_v2/impl/ios/atomic_reference.h b/cpp/platform/impl/ios/atomic_reference.h similarity index 72% rename from cpp/platform_v2/impl/ios/atomic_reference.h rename to cpp/platform/impl/ios/atomic_reference.h index 49bb2849..5f2a9c2e 100644 --- a/cpp/platform_v2/impl/ios/atomic_reference.h +++ b/cpp/platform/impl/ios/atomic_reference.h @@ -1,10 +1,10 @@ -#ifndef PLATFORM_V2_IMPL_IOS_ATOMIC_REFERENCE_H_ -#define PLATFORM_V2_IMPL_IOS_ATOMIC_REFERENCE_H_ +#ifndef PLATFORM_IMPL_IOS_ATOMIC_REFERENCE_H_ +#define PLATFORM_IMPL_IOS_ATOMIC_REFERENCE_H_ #include #include -#include "platform_v2/api/atomic_reference.h" +#include "platform/api/atomic_reference.h" namespace location { namespace nearby { @@ -30,4 +30,4 @@ class AtomicUint32 : public api::AtomicUint32 { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_IOS_ATOMIC_REFERENCE_H_ +#endif // PLATFORM_IMPL_IOS_ATOMIC_REFERENCE_H_ diff --git a/cpp/platform_v2/impl/ios/condition_variable.h b/cpp/platform/impl/ios/condition_variable.h similarity index 71% rename from cpp/platform_v2/impl/ios/condition_variable.h rename to cpp/platform/impl/ios/condition_variable.h index 4df6893a..2903a423 100644 --- a/cpp/platform_v2/impl/ios/condition_variable.h +++ b/cpp/platform/impl/ios/condition_variable.h @@ -1,9 +1,9 @@ -#ifndef PLATFORM_V2_IMPL_IOS_CONDITION_VARIABLE_H_ -#define PLATFORM_V2_IMPL_IOS_CONDITION_VARIABLE_H_ +#ifndef PLATFORM_IMPL_IOS_CONDITION_VARIABLE_H_ +#define PLATFORM_IMPL_IOS_CONDITION_VARIABLE_H_ -#include "platform_v2/api/condition_variable.h" -#include "platform_v2/base/exception.h" -#include "platform_v2/impl/ios/mutex.h" +#include "platform/api/condition_variable.h" +#include "platform/base/exception.h" +#include "platform/impl/ios/mutex.h" #include "absl/synchronization/mutex.h" namespace location { @@ -34,4 +34,4 @@ class ConditionVariable : public api::ConditionVariable { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_IOS_CONDITION_VARIABLE_H_ +#endif // PLATFORM_IMPL_IOS_CONDITION_VARIABLE_H_ diff --git a/cpp/platform_v2/impl/ios/count_down_latch.h b/cpp/platform/impl/ios/count_down_latch.h similarity index 88% rename from cpp/platform_v2/impl/ios/count_down_latch.h rename to cpp/platform/impl/ios/count_down_latch.h index a06bcc45..bf3eca4b 100644 --- a/cpp/platform_v2/impl/ios/count_down_latch.h +++ b/cpp/platform/impl/ios/count_down_latch.h @@ -1,7 +1,7 @@ -#ifndef PLATFORM_V2_IMPL_IOS_COUNT_DOWN_LATCH_H_ -#define PLATFORM_V2_IMPL_IOS_COUNT_DOWN_LATCH_H_ +#ifndef PLATFORM_IMPL_IOS_COUNT_DOWN_LATCH_H_ +#define PLATFORM_IMPL_IOS_COUNT_DOWN_LATCH_H_ -#include "platform_v2/api/count_down_latch.h" +#include "platform/api/count_down_latch.h" #include "absl/base/thread_annotations.h" #include "absl/synchronization/mutex.h" #include "absl/time/clock.h" @@ -52,4 +52,4 @@ class CountDownLatch final : public api::CountDownLatch { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_IOS_COUNT_DOWN_LATCH_H_ +#endif // PLATFORM_IMPL_IOS_COUNT_DOWN_LATCH_H_ diff --git a/cpp/platform_v2/impl/ios/log_message.h b/cpp/platform/impl/ios/log_message.h similarity index 70% rename from cpp/platform_v2/impl/ios/log_message.h rename to cpp/platform/impl/ios/log_message.h index dd0a0c2a..6e3048d6 100644 --- a/cpp/platform_v2/impl/ios/log_message.h +++ b/cpp/platform/impl/ios/log_message.h @@ -1,8 +1,8 @@ -#ifndef PLATFORM_V2_IMPL_IOS_LOG_MESSAGE_H_ -#define PLATFORM_V2_IMPL_IOS_LOG_MESSAGE_H_ +#ifndef PLATFORM_IMPL_IOS_LOG_MESSAGE_H_ +#define PLATFORM_IMPL_IOS_LOG_MESSAGE_H_ #include "base/logging.h" -#include "platform_v2/api/log_message.h" +#include "platform/api/log_message.h" namespace location { namespace nearby { @@ -25,4 +25,4 @@ class LogMessage : public api::LogMessage { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_IOS_LOG_MESSAGE_H_ +#endif // PLATFORM_IMPL_IOS_LOG_MESSAGE_H_ diff --git a/cpp/platform_v2/impl/ios/log_message.mm b/cpp/platform/impl/ios/log_message.mm similarity index 96% rename from cpp/platform_v2/impl/ios/log_message.mm rename to cpp/platform/impl/ios/log_message.mm index 0e6ac13c..350e93ef 100644 --- a/cpp/platform_v2/impl/ios/log_message.mm +++ b/cpp/platform/impl/ios/log_message.mm @@ -1,4 +1,4 @@ -#include "platform_v2/impl/ios/log_message.h" +#include "platform/impl/ios/log_message.h" #include diff --git a/cpp/platform_v2/impl/ios/multi_thread_executor.h b/cpp/platform/impl/ios/multi_thread_executor.h similarity index 82% rename from cpp/platform_v2/impl/ios/multi_thread_executor.h rename to cpp/platform/impl/ios/multi_thread_executor.h index e665df62..6450c46d 100644 --- a/cpp/platform_v2/impl/ios/multi_thread_executor.h +++ b/cpp/platform/impl/ios/multi_thread_executor.h @@ -1,10 +1,10 @@ -#ifndef PLATFORM_V2_IMPL_IOS_MULTI_THREAD_EXECUTOR_H_ -#define PLATFORM_V2_IMPL_IOS_MULTI_THREAD_EXECUTOR_H_ +#ifndef PLATFORM_IMPL_IOS_MULTI_THREAD_EXECUTOR_H_ +#define PLATFORM_IMPL_IOS_MULTI_THREAD_EXECUTOR_H_ #include -#include "platform_v2/api/submittable_executor.h" -#include "platform_v2/impl/ios/count_down_latch.h" +#include "platform/api/submittable_executor.h" +#include "platform/impl/ios/count_down_latch.h" #include "absl/time/clock.h" #include "thread/threadpool.h" @@ -54,4 +54,4 @@ class MultiThreadExecutor : public api::SubmittableExecutor { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_IOS_MULTI_THREAD_EXECUTOR_H_ +#endif // PLATFORM_IMPL_IOS_MULTI_THREAD_EXECUTOR_H_ diff --git a/cpp/platform_v2/impl/ios/mutex.h b/cpp/platform/impl/ios/mutex.h similarity index 84% rename from cpp/platform_v2/impl/ios/mutex.h rename to cpp/platform/impl/ios/mutex.h index 2986869f..5e034068 100644 --- a/cpp/platform_v2/impl/ios/mutex.h +++ b/cpp/platform/impl/ios/mutex.h @@ -1,8 +1,8 @@ -#ifndef PLATFORM_V2_IMPL_IOS_MUTEX_H_ -#define PLATFORM_V2_IMPL_IOS_MUTEX_H_ +#ifndef PLATFORM_IMPL_IOS_MUTEX_H_ +#define PLATFORM_IMPL_IOS_MUTEX_H_ -#include "platform_v2/api/mutex.h" -#include "platform_v2/impl/shared/posix_mutex.h" +#include "platform/api/mutex.h" +#include "platform/impl/shared/posix_mutex.h" #include "absl/synchronization/mutex.h" namespace location { @@ -44,4 +44,4 @@ class ABSL_LOCKABLE RecursiveMutex : public posix::Mutex { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_IOS_MUTEX_H_ +#endif // PLATFORM_IMPL_IOS_MUTEX_H_ diff --git a/cpp/platform_v2/impl/ios/platform.mm b/cpp/platform/impl/ios/platform.mm similarity index 79% rename from cpp/platform_v2/impl/ios/platform.mm rename to cpp/platform/impl/ios/platform.mm index dabd01d4..4ca04cae 100644 --- a/cpp/platform_v2/impl/ios/platform.mm +++ b/cpp/platform/impl/ios/platform.mm @@ -1,26 +1,26 @@ -#include "platform_v2/api/platform.h" +#include "platform/api/platform.h" #include #include -#include "platform_v2/api/atomic_boolean.h" -#include "platform_v2/api/atomic_reference.h" -#include "platform_v2/api/condition_variable.h" -#include "platform_v2/api/count_down_latch.h" -#include "platform_v2/api/log_message.h" -#include "platform_v2/api/mutex.h" -#include "platform_v2/api/scheduled_executor.h" -#include "platform_v2/api/submittable_executor.h" -#include "platform_v2/impl/ios/atomic_boolean.h" -#include "platform_v2/impl/ios/atomic_reference.h" -#include "platform_v2/impl/ios/condition_variable.h" -#include "platform_v2/impl/ios/count_down_latch.h" -#include "platform_v2/impl/ios/log_message.h" -#include "platform_v2/impl/ios/multi_thread_executor.h" -#include "platform_v2/impl/ios/mutex.h" -#include "platform_v2/impl/ios/scheduled_executor.h" -#include "platform_v2/impl/ios/single_thread_executor.h" -#include "platform_v2/impl/shared/file.h" +#include "platform/api/atomic_boolean.h" +#include "platform/api/atomic_reference.h" +#include "platform/api/condition_variable.h" +#include "platform/api/count_down_latch.h" +#include "platform/api/log_message.h" +#include "platform/api/mutex.h" +#include "platform/api/scheduled_executor.h" +#include "platform/api/submittable_executor.h" +#include "platform/impl/ios/atomic_boolean.h" +#include "platform/impl/ios/atomic_reference.h" +#include "platform/impl/ios/condition_variable.h" +#include "platform/impl/ios/count_down_latch.h" +#include "platform/impl/ios/log_message.h" +#include "platform/impl/ios/multi_thread_executor.h" +#include "platform/impl/ios/mutex.h" +#include "platform/impl/ios/scheduled_executor.h" +#include "platform/impl/ios/single_thread_executor.h" +#include "platform/impl/shared/file.h" #include "absl/memory/memory.h" namespace location { diff --git a/cpp/platform_v2/impl/ios/scheduled_executor.h b/cpp/platform/impl/ios/scheduled_executor.h similarity index 70% rename from cpp/platform_v2/impl/ios/scheduled_executor.h rename to cpp/platform/impl/ios/scheduled_executor.h index 6fb08fd7..f609f137 100644 --- a/cpp/platform_v2/impl/ios/scheduled_executor.h +++ b/cpp/platform/impl/ios/scheduled_executor.h @@ -1,13 +1,13 @@ -#ifndef PLATFORM_V2_IMPL_IOS_SCHEDULED_EXECUTOR_H_ -#define PLATFORM_V2_IMPL_IOS_SCHEDULED_EXECUTOR_H_ +#ifndef PLATFORM_IMPL_IOS_SCHEDULED_EXECUTOR_H_ +#define PLATFORM_IMPL_IOS_SCHEDULED_EXECUTOR_H_ #include #include -#include "platform_v2/api/cancelable.h" -#include "platform_v2/api/scheduled_executor.h" -#include "platform_v2/base/runnable.h" -#include "platform_v2/impl/ios/single_thread_executor.h" +#include "platform/api/cancelable.h" +#include "platform/api/scheduled_executor.h" +#include "platform/base/runnable.h" +#include "platform/impl/ios/single_thread_executor.h" #include "absl/time/clock.h" #include "thread/threadpool.h" @@ -40,4 +40,4 @@ class ScheduledExecutor final : public api::ScheduledExecutor { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_IOS_SCHEDULED_EXECUTOR_H_ +#endif // PLATFORM_IMPL_IOS_SCHEDULED_EXECUTOR_H_ diff --git a/cpp/platform_v2/impl/ios/scheduled_executor.mm b/cpp/platform/impl/ios/scheduled_executor.mm similarity index 91% rename from cpp/platform_v2/impl/ios/scheduled_executor.mm rename to cpp/platform/impl/ios/scheduled_executor.mm index 6d850b06..9955a021 100644 --- a/cpp/platform_v2/impl/ios/scheduled_executor.mm +++ b/cpp/platform/impl/ios/scheduled_executor.mm @@ -1,10 +1,10 @@ -#include "platform_v2/impl/ios/scheduled_executor.h" +#include "platform/impl/ios/scheduled_executor.h" #include #include -#include "platform_v2/api/cancelable.h" -#include "platform_v2/base/runnable.h" +#include "platform/api/cancelable.h" +#include "platform/base/runnable.h" #include "absl/time/clock.h" namespace location { diff --git a/cpp/platform_v2/impl/ios/single_thread_executor.h b/cpp/platform/impl/ios/single_thread_executor.h similarity index 57% rename from cpp/platform_v2/impl/ios/single_thread_executor.h rename to cpp/platform/impl/ios/single_thread_executor.h index be5d99e0..ac72d482 100644 --- a/cpp/platform_v2/impl/ios/single_thread_executor.h +++ b/cpp/platform/impl/ios/single_thread_executor.h @@ -1,7 +1,7 @@ -#ifndef PLATFORM_V2_IMPL_IOS_SINGLE_THREAD_EXECUTOR_H_ -#define PLATFORM_V2_IMPL_IOS_SINGLE_THREAD_EXECUTOR_H_ +#ifndef PLATFORM_IMPL_IOS_SINGLE_THREAD_EXECUTOR_H_ +#define PLATFORM_IMPL_IOS_SINGLE_THREAD_EXECUTOR_H_ -#include "platform_v2/impl/ios/multi_thread_executor.h" +#include "platform/impl/ios/multi_thread_executor.h" namespace location { namespace nearby { @@ -17,4 +17,4 @@ class SingleThreadExecutor final : public MultiThreadExecutor { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_IOS_SINGLE_THREAD_EXECUTOR_H_ +#endif // PLATFORM_IMPL_IOS_SINGLE_THREAD_EXECUTOR_H_ diff --git a/cpp/platform/impl/sample/BUILD b/cpp/platform/impl/sample/BUILD deleted file mode 100644 index fdba4e14..00000000 --- a/cpp/platform/impl/sample/BUILD +++ /dev/null @@ -1,19 +0,0 @@ -cc_library( - name = "sample_platform", - srcs = [ - "atomic_reference_impl.h", - "sample_platform.cc", - "settable_future_impl.h", - ], - visibility = ["//visibility:private"], - deps = [ - "//platform:types", - "//platform:utils", - "//platform/api", - "//platform/impl/shared:file", - "//platform/impl/shared/sample:sample_wifi_medium", - "//platform/port:string", - "//absl/time", - "//absl/types:any", - ], -) diff --git a/cpp/platform/impl/sample/atomic_reference_impl.h b/cpp/platform/impl/sample/atomic_reference_impl.h deleted file mode 100644 index 8479cc52..00000000 --- a/cpp/platform/impl/sample/atomic_reference_impl.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef PLATFORM_IMPL_SAMPLE_ATOMIC_REFERENCE_IMPL_H_ -#define PLATFORM_IMPL_SAMPLE_ATOMIC_REFERENCE_IMPL_H_ - -#include "platform/api/atomic_reference_def.h" -#include "absl/types/any.h" - -namespace location { -namespace nearby { -namespace platform { - -// Provide implementation for absl::any. -class AtomicReferenceImpl : public AtomicReference { - public: - explicit AtomicReferenceImpl(absl::any initial_value) {} - ~AtomicReferenceImpl() override = default; - - absl::any get() override { return {}; } - void set(absl::any value) override {} -}; - -} // namespace platform -} // namespace nearby -} // namespace location - -#endif // PLATFORM_IMPL_SAMPLE_ATOMIC_REFERENCE_IMPL_H_ diff --git a/cpp/platform/impl/sample/sample_platform.cc b/cpp/platform/impl/sample/sample_platform.cc deleted file mode 100644 index 4ea9a98d..00000000 --- a/cpp/platform/impl/sample/sample_platform.cc +++ /dev/null @@ -1,138 +0,0 @@ -#include - -#include "platform/api/atomic_boolean.h" -#include "platform/api/atomic_reference_def.h" -#include "platform/api/ble.h" -#include "platform/api/ble_v2.h" -#include "platform/api/bluetooth_adapter.h" -#include "platform/api/bluetooth_classic.h" -#include "platform/api/condition_variable.h" -#include "platform/api/count_down_latch.h" -#include "platform/api/hash_utils.h" -#include "platform/api/lock.h" -#include "platform/api/platform.h" -#include "platform/api/server_sync.h" -#include "platform/api/settable_future_def.h" -#include "platform/api/submittable_executor_def.h" -#include "platform/api/system_clock.h" -#include "platform/api/thread_utils.h" -#include "platform/api/wifi.h" -#include "platform/cancelable.h" -#include "platform/impl/sample/atomic_reference_impl.h" -#include "platform/impl/sample/settable_future_impl.h" -#include "platform/impl/shared/file_impl.h" -#include "platform/impl/shared/sample/sample_wifi_medium.h" -#include "platform/port/string.h" -#include "platform/ptr.h" -#include "platform/runnable.h" -#include "absl/types/any.h" - -namespace location { -namespace nearby { -namespace platform { - -namespace { -std::string getPayloadPath(std::int64_t payload_id) { - return "/tmp/sample-" + std::to_string(payload_id); -} -} // namespace - -Ptr ImplementationPlatform::createScheduledExecutor() { - return Ptr{}; -} - -Ptr ImplementationPlatform::createSingleThreadExecutor() { - return Ptr{}; -} - -Ptr ImplementationPlatform::createMultiThreadExecutor( - int max_concurrency) { - return Ptr{}; -} - -Ptr> -ImplementationPlatform::createAtomicReferenceAny(absl::any initial_value) { - return Ptr>( - new AtomicReferenceImpl(initial_value)); -} - -Ptr> -ImplementationPlatform::createSettableFutureAny() { - return Ptr>(new SettableFutureImpl{}); -} - -Ptr ImplementationPlatform::createBluetoothAdapter() { - return Ptr{}; -} - -Ptr ImplementationPlatform::createWifiMedium() { - return Ptr(); -} - -Ptr ImplementationPlatform::createCountDownLatch( - std::int32_t count) { - return Ptr{}; -} - -Ptr ImplementationPlatform::createThreadUtils() { - return Ptr{}; -} - -Ptr ImplementationPlatform::createSystemClock() { - return Ptr{}; -} - -Ptr ImplementationPlatform::createAtomicBoolean( - bool initial_value) { - return Ptr{}; -} - -Ptr ImplementationPlatform::createInputFile( - std::int64_t payload_id, std::int64_t total_size) { - return MakePtr(new InputFileImpl(getPayloadPath(payload_id), total_size)); -} - -Ptr ImplementationPlatform::createOutputFile( - std::int64_t payload_id) { - return MakePtr(new OutputFileImpl(getPayloadPath(payload_id))); -} - -Ptr -ImplementationPlatform::createBluetoothClassicMedium() { - return Ptr(); -} - -Ptr ImplementationPlatform::createBLEMedium() { - return Ptr(); -} - -Ptr ImplementationPlatform::createBLEMediumV2() { - return Ptr(); -} - -Ptr ImplementationPlatform::createServerSyncMedium() { - return Ptr{}; -} - -Ptr -ImplementationPlatform::createWebRtcSignalingMessenger( - const std::string& self_id) { - return Ptr{}; -} - -Ptr ImplementationPlatform::createLock() { return Ptr{}; } - -Ptr ImplementationPlatform::createConditionVariable( - Ptr lock) { - return Ptr{}; -} - -Ptr ImplementationPlatform::createHashUtils() { - return Ptr{}; -} - -std::string ImplementationPlatform::getDeviceId() { return "sample"; } - -} // namespace platform -} // namespace nearby -} // namespace location diff --git a/cpp/platform/impl/sample/settable_future_impl.h b/cpp/platform/impl/sample/settable_future_impl.h deleted file mode 100644 index 16f82672..00000000 --- a/cpp/platform/impl/sample/settable_future_impl.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef PLATFORM_IMPL_SAMPLE_SETTABLE_FUTURE_IMPL_H_ -#define PLATFORM_IMPL_SAMPLE_SETTABLE_FUTURE_IMPL_H_ - -#include "platform/api/settable_future_def.h" -#include "absl/types/any.h" - -namespace location { -namespace nearby { -namespace platform { - -class SettableFutureImpl : public SettableFuture { - public: - explicit SettableFutureImpl() = default; - ~SettableFutureImpl() override = default; - - bool set(absl::any value) override { return true; } - - bool setException(Exception exception) override { return true; } - - void addListener(Ptr runnable, Executor* executor) override {} - - ExceptionOr get() override { - return ExceptionOr{Exception{Exception::kFailed}}; - } - - ExceptionOr get(std::int64_t timeout_ms) override { - return ExceptionOr{Exception{Exception::kFailed}}; - } -}; - -} // namespace platform -} // namespace nearby -} // namespace location - -#endif // PLATFORM_IMPL_SAMPLE_SETTABLE_FUTURE_IMPL_H_ diff --git a/cpp/platform/impl/shared/BUILD b/cpp/platform/impl/shared/BUILD index cd000b3d..ea027422 100644 --- a/cpp/platform/impl/shared/BUILD +++ b/cpp/platform/impl/shared/BUILD @@ -1,18 +1,16 @@ cc_library( - name = "posix_lock", + name = "posix_mutex", srcs = [ - "posix_lock.cc", + "posix_mutex.cc", ], hdrs = [ - "posix_lock.h", + "posix_mutex.h", ], visibility = [ "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", "//platform/impl:__subpackages__", ], - deps = [ - "//platform/api", - ], + deps = ["//platform/api:types"], ) cc_library( @@ -25,49 +23,35 @@ cc_library( ], visibility = [ "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", - "//platform/impl:__subpackages__", ], deps = [ - ":posix_lock", - "//platform:types", - "//platform/api:condition_variable", + ":posix_mutex", + "//platform/api:types", ], ) -cc_library( - name = "atomic_boolean", - hdrs = ["atomic_boolean_impl.h"], - visibility = [ - "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", - "//platform/impl:__subpackages__", - ], - deps = ["//platform/api"], -) - cc_library( name = "file", - srcs = ["file_impl.cc"], - hdrs = ["file_impl.h"], + srcs = ["file.cc"], + hdrs = ["file.h"], visibility = [ "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", - "//core:__subpackages__", "//platform/impl:__subpackages__", ], deps = [ - "//platform:types", - "//platform/api", + "//platform/api:types", + "//platform/base", + "//absl/strings", ], ) cc_test( name = "file_test", - timeout = "short", - srcs = [ - "file_impl_test.cc", - ], + srcs = ["file_test.cc"], deps = [ ":file", "//file/util:temp_path", + "//platform/base", "//testing/base/public:gunit_main", "//absl/strings", ], diff --git a/cpp/platform/impl/shared/BUILD.orig b/cpp/platform/impl/shared/BUILD.orig new file mode 100644 index 00000000..05e5ff1b --- /dev/null +++ b/cpp/platform/impl/shared/BUILD.orig @@ -0,0 +1,71 @@ +cc_library( + name = "posix_lock", + srcs = [ + "posix_lock.cc", + ], + hdrs = [ + "posix_lock.h", + ], + visibility = [ + "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", + "//platform/impl:__subpackages__", + ], + deps = [ + "//platform/api", + ], +) + +cc_library( + name = "posix_condition_variable", + srcs = [ + "posix_condition_variable.cc", + ], + hdrs = [ + "posix_condition_variable.h", + ], + visibility = [ + "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", + "//platform/impl:__subpackages__", + ], + deps = [ + ":posix_lock", + "//platform:types", + "//platform/api:condition_variable", + ], +) + +cc_library( + name = "atomic_boolean", + hdrs = ["atomic_boolean_impl.h"], + visibility = ["//platform/impl:__subpackages__"], + deps = ["//platform/api"], +) + +cc_library( + name = "file", + srcs = ["file_impl.cc"], + hdrs = ["file_impl.h"], + visibility = [ + "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", + "//core:__subpackages__", + "//platform/impl:__subpackages__", + ], + deps = [ + "//platform:types", + "//platform/api", + ], +) + +cc_test( + name = "file_test", + timeout = "short", + srcs = [ + "file_impl_test.cc", + ], + deps = [ + ":file", + "//file/util:temp_path", + "//testing/base/public:gunit_main", + "//absl/strings", + ], +) diff --git a/cpp/platform/impl/shared/atomic_boolean_impl.h b/cpp/platform/impl/shared/atomic_boolean_impl.h deleted file mode 100644 index 8f28e64a..00000000 --- a/cpp/platform/impl/shared/atomic_boolean_impl.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef PLATFORM_IMPL_SHARED_ATOMIC_BOOLEAN_IMPL_H_ -#define PLATFORM_IMPL_SHARED_ATOMIC_BOOLEAN_IMPL_H_ - -#include - -#include "platform/api/atomic_boolean.h" - -namespace location { -namespace nearby { - -class AtomicBooleanImpl : public AtomicBoolean { - public: - explicit AtomicBooleanImpl(bool initial_value) : value_(initial_value) {} - ~AtomicBooleanImpl() override = default; - - // AtomicBoolean: - bool get() override { - return value_.load(); - } - - // AtomicBoolean: - void set(bool value) override { - value_.store(value); - } - - private: - std::atomic_bool value_; -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_IMPL_SHARED_ATOMIC_BOOLEAN_IMPL_H_ diff --git a/cpp/platform_v2/impl/shared/file.cc b/cpp/platform/impl/shared/file.cc similarity index 95% rename from cpp/platform_v2/impl/shared/file.cc rename to cpp/platform/impl/shared/file.cc index 50571b02..0d47aa24 100644 --- a/cpp/platform_v2/impl/shared/file.cc +++ b/cpp/platform/impl/shared/file.cc @@ -1,9 +1,9 @@ -#include "platform_v2/impl/shared/file.h" +#include "platform/impl/shared/file.h" #include #include -#include "platform_v2/base/exception.h" +#include "platform/base/exception.h" #include "absl/strings/string_view.h" namespace location { diff --git a/cpp/platform_v2/impl/shared/file.h b/cpp/platform/impl/shared/file.h similarity index 82% rename from cpp/platform_v2/impl/shared/file.h rename to cpp/platform/impl/shared/file.h index 69e491ce..0b8ab946 100644 --- a/cpp/platform_v2/impl/shared/file.h +++ b/cpp/platform/impl/shared/file.h @@ -1,12 +1,12 @@ -#ifndef PLATFORM_V2_IMPL_SHARED_FILE_H_ -#define PLATFORM_V2_IMPL_SHARED_FILE_H_ +#ifndef PLATFORM_IMPL_SHARED_FILE_H_ +#define PLATFORM_IMPL_SHARED_FILE_H_ #include #include -#include "platform_v2/api/input_file.h" -#include "platform_v2/api/output_file.h" -#include "platform_v2/base/exception.h" +#include "platform/api/input_file.h" +#include "platform/api/output_file.h" +#include "platform/base/exception.h" #include "absl/strings/string_view.h" namespace location { @@ -50,4 +50,4 @@ class OutputFile final : public api::OutputFile { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_SHARED_FILE_H_ +#endif // PLATFORM_IMPL_SHARED_FILE_H_ diff --git a/cpp/platform/impl/shared/file_impl.cc b/cpp/platform/impl/shared/file_impl.cc deleted file mode 100644 index 2a21e8ea..00000000 --- a/cpp/platform/impl/shared/file_impl.cc +++ /dev/null @@ -1,75 +0,0 @@ -#include "platform/impl/shared/file_impl.h" - -#include -#include - -namespace location { -namespace nearby { - -// InputFile - -InputFileImpl::InputFileImpl(const std::string& path, std::int64_t size) - : file_(path), path_(path), total_size_(size) {} - -ExceptionOr> InputFileImpl::read(int64_t size) { - if (!file_.is_open()) { - return ExceptionOr>(Exception::IO); - } - - if (file_.peek() == EOF) { - return ExceptionOr>(ConstPtr()); - } - - if (!file_.good()) { - return ExceptionOr>(Exception::IO); - } - - std::unique_ptr read_bytes {new char [size]}; - file_.read(read_bytes.get(), static_cast(size)); - auto num_bytes_read = file_.gcount(); - if (num_bytes_read == 0) { - return ExceptionOr>(Exception::IO); - } - - return ExceptionOr>( - MakeConstPtr(new ByteArray(read_bytes.get(), num_bytes_read))); -} - -std::string InputFileImpl::getFilePath() const { return path_; } - -std::int64_t InputFileImpl::getTotalSize() const { return total_size_; } - -void InputFileImpl::close() { - if (file_.is_open()) { - file_.close(); - } -} - -// OutputFile - -OutputFileImpl::OutputFileImpl(const std::string& path) : file_(path) {} - -Exception::Value OutputFileImpl::write(ConstPtr data) { - ScopedPtr> scoped_data(data); - - if (!file_.is_open()) { - return Exception::IO; - } - - if (!file_.good()) { - return Exception::IO; - } - - file_.write(data->getData(), data->size()); - file_.flush(); - return file_.good() ? Exception::NONE : Exception::IO; -} - -void OutputFileImpl::close() { - if (file_.is_open()) { - file_.close(); - } -} - -} // namespace nearby -} // namespace location diff --git a/cpp/platform/impl/shared/file_impl.h b/cpp/platform/impl/shared/file_impl.h deleted file mode 100644 index 5c2f33f7..00000000 --- a/cpp/platform/impl/shared/file_impl.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef PLATFORM_IMPL_SHARED_FILE_IMPL_H_ -#define PLATFORM_IMPL_SHARED_FILE_IMPL_H_ - -#include -#include - -#include "platform/api/input_file.h" -#include "platform/api/output_file.h" -#include "platform/exception.h" -#include "platform/ptr.h" - -namespace location { -namespace nearby { - -class InputFileImpl final : public InputFile { - public: - InputFileImpl(const std::string& path, std::int64_t size); - ~InputFileImpl() override {} - - ExceptionOr> read(std::int64_t size) override; - std::string getFilePath() const override; - std::int64_t getTotalSize() const override; - void close() override; - - private: - std::ifstream file_; - const std::string path_; - const std::int64_t total_size_; -}; - -class OutputFileImpl final : public OutputFile { - public: - explicit OutputFileImpl(const std::string& path); - ~OutputFileImpl() override {} - - Exception::Value write(ConstPtr data) override; - void close() override; - - private: - std::ofstream file_; -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_IMPL_SHARED_FILE_IMPL_H_ diff --git a/cpp/platform/impl/shared/file_impl_test.cc b/cpp/platform/impl/shared/file_impl_test.cc deleted file mode 100644 index bea472a0..00000000 --- a/cpp/platform/impl/shared/file_impl_test.cc +++ /dev/null @@ -1,134 +0,0 @@ -#include "platform/impl/shared/file_impl.h" - -#include -#include -#include -#include - -#include "file/util/temp_path.h" -#include "gtest/gtest.h" -#include "absl/strings/string_view.h" - -namespace location { -namespace nearby { - -class FileImplTest : public ::testing::Test { - protected: - void SetUp() override { - temp_path_ = std::make_unique(TempPath::Local); - path_ = temp_path_->path() + "/file.txt"; - std::ofstream output_file(path_); - file_ = std::fstream(path_, std::fstream::in | std::fstream::out); - } - - void WriteToFile(absl::string_view text) { - file_ << text; - file_.flush(); - size_ += text.size(); - } - - size_t GetSize() const { return size_; } - - void AssertEquals(const ExceptionOr>& bytes, - const std::string& expected) { - ASSERT_TRUE(bytes.ok()); - ScopedPtr> byte_array(bytes.result()); - ASSERT_STREQ(byte_array->getData(), expected.c_str()); - ASSERT_EQ(byte_array->size(), expected.length()); - } - - void AssertNull(const ExceptionOr>& bytes) { - ASSERT_TRUE(bytes.ok()); - ASSERT_TRUE(bytes.result().isNull()); - } - - static constexpr int64_t kMaxSize = 3; - - std::unique_ptr temp_path_; - std::string path_; - std::fstream file_; - size_t size_ = 0; -}; - -TEST_F(FileImplTest, InputFile_NonExistentPath) { - InputFileImpl input_file("/not/a/valid/path.txt", GetSize()); - ExceptionOr> read_result = input_file.read(kMaxSize); - ASSERT_FALSE(read_result.ok()); - ASSERT_EQ(read_result.exception(), Exception::IO); -} - -TEST_F(FileImplTest, InputFile_GetFilePath) { - InputFileImpl input_file(path_, GetSize()); - ASSERT_EQ(input_file.getFilePath(), path_); -} - -TEST_F(FileImplTest, InputFile_EmptyFileEOF) { - InputFileImpl input_file(path_, GetSize()); - AssertNull(input_file.read(kMaxSize)); -} - -TEST_F(FileImplTest, InputFile_ReadWorks) { - WriteToFile("abc"); - InputFileImpl input_file(path_, GetSize()); - auto read_data = input_file.read(kMaxSize); - read_data.result().destroy(); - SUCCEED(); -} - -TEST_F(FileImplTest, InputFile_ReadUntilEOF) { - WriteToFile("abc"); - InputFileImpl input_file(path_, GetSize()); - AssertEquals(input_file.read(kMaxSize), "abc"); - AssertNull(input_file.read(kMaxSize)); -} - -TEST_F(FileImplTest, InputFile_ReadWithSize) { - WriteToFile("abc"); - InputFileImpl input_file(path_, GetSize()); - AssertEquals(input_file.read(2), "ab"); - AssertEquals(input_file.read(1), "c"); - AssertNull(input_file.read(kMaxSize)); -} - -TEST_F(FileImplTest, InputFile_GetTotalSize) { - WriteToFile("abc"); - InputFileImpl input_file(path_, GetSize()); - EXPECT_EQ(input_file.getTotalSize(), 3); - AssertEquals(input_file.read(1), "a"); - EXPECT_EQ(input_file.getTotalSize(), 3); -} - -TEST_F(FileImplTest, InputFile_Close) { - WriteToFile("abc"); - InputFileImpl input_file(path_, GetSize()); - input_file.close(); - ExceptionOr> read_result = input_file.read(kMaxSize); - ASSERT_FALSE(read_result.ok()); - ASSERT_EQ(read_result.exception(), Exception::IO); -} - -TEST_F(FileImplTest, OutputFile_NonExistentPath) { - OutputFileImpl output_file("/not/a/valid/path.txt"); - ConstPtr bytes = MakeConstPtr(new ByteArray("a", 1)); - Exception::Value write_result = output_file.write(bytes); - ASSERT_EQ(write_result, Exception::IO); -} - -TEST_F(FileImplTest, OutputFile_Write) { - OutputFileImpl output_file(path_); - ConstPtr bytes1 = MakeConstPtr(new ByteArray("a", 1)); - ConstPtr bytes2 = MakeConstPtr(new ByteArray("bc", 2)); - ASSERT_EQ(output_file.write(bytes1), Exception::NONE); - ASSERT_EQ(output_file.write(bytes2), Exception::NONE); - InputFileImpl input_file(path_, GetSize()); - AssertEquals(input_file.read(kMaxSize), "abc"); -} - -TEST_F(FileImplTest, OutputFile_Close) { - OutputFileImpl output_file(path_); - output_file.close(); - ConstPtr bytes = MakeConstPtr(new ByteArray("a", 1)); - ASSERT_EQ(output_file.write(bytes), Exception::IO); -} -} // namespace nearby -} // namespace location diff --git a/cpp/platform_v2/impl/shared/file_test.cc b/cpp/platform/impl/shared/file_test.cc similarity index 97% rename from cpp/platform_v2/impl/shared/file_test.cc rename to cpp/platform/impl/shared/file_test.cc index e97b5ad0..ac23e69a 100644 --- a/cpp/platform_v2/impl/shared/file_test.cc +++ b/cpp/platform/impl/shared/file_test.cc @@ -1,4 +1,4 @@ -#include "platform_v2/impl/shared/file.h" +#include "platform/impl/shared/file.h" #include #include @@ -6,7 +6,7 @@ #include #include "file/util/temp_path.h" -#include "platform_v2/base/byte_array.h" +#include "platform/base/byte_array.h" #include "gtest/gtest.h" #include "absl/strings/string_view.h" diff --git a/cpp/platform/impl/shared/posix_condition_variable.cc b/cpp/platform/impl/shared/posix_condition_variable.cc index 72b4450e..ca195df9 100644 --- a/cpp/platform/impl/shared/posix_condition_variable.cc +++ b/cpp/platform/impl/shared/posix_condition_variable.cc @@ -2,27 +2,29 @@ namespace location { namespace nearby { +namespace posix { -PosixConditionVariable::PosixConditionVariable(Ptr lock) - : lock_(lock), attr_(), cond_() { +ConditionVariable::ConditionVariable(Mutex* mutex) + : mutex_(mutex), attr_(), cond_() { pthread_condattr_init(&attr_); pthread_cond_init(&cond_, &attr_); } -PosixConditionVariable::~PosixConditionVariable() { +ConditionVariable::~ConditionVariable() { pthread_cond_destroy(&cond_); pthread_condattr_destroy(&attr_); } -void PosixConditionVariable::notify() { pthread_cond_broadcast(&cond_); } +void ConditionVariable::Notify() { pthread_cond_broadcast(&cond_); } -Exception::Value PosixConditionVariable::wait() { - pthread_cond_wait(&cond_, &(lock_->mutex_)); +Exception ConditionVariable::Wait() { + pthread_cond_wait(&cond_, &(mutex_->mutex_)); - return Exception::kSuccess; + return {Exception::kSuccess}; } +} // namespace posix } // namespace nearby } // namespace location diff --git a/cpp/platform/impl/shared/posix_condition_variable.h b/cpp/platform/impl/shared/posix_condition_variable.h index ea558558..35603fa5 100644 --- a/cpp/platform/impl/shared/posix_condition_variable.h +++ b/cpp/platform/impl/shared/posix_condition_variable.h @@ -4,26 +4,27 @@ #include #include "platform/api/condition_variable.h" -#include "platform/impl/shared/posix_lock.h" -#include "platform/ptr.h" +#include "platform/impl/shared/posix_mutex.h" namespace location { namespace nearby { +namespace posix { -class PosixConditionVariable : public ConditionVariable { +class ConditionVariable : public api::ConditionVariable { public: - explicit PosixConditionVariable(Ptr lock); - ~PosixConditionVariable() override; + explicit ConditionVariable(Mutex* mutex); + ~ConditionVariable() override; - void notify() override; - Exception::Value wait() override; + void Notify() override; + Exception Wait() override; private: - Ptr lock_; + Mutex* mutex_; pthread_condattr_t attr_; pthread_cond_t cond_; }; +} // namespace posix } // namespace nearby } // namespace location diff --git a/cpp/platform/impl/shared/posix_lock.cc b/cpp/platform/impl/shared/posix_lock.cc deleted file mode 100644 index 3bb154b6..00000000 --- a/cpp/platform/impl/shared/posix_lock.cc +++ /dev/null @@ -1,24 +0,0 @@ -#include "platform/impl/shared/posix_lock.h" - -namespace location { -namespace nearby { - -PosixLock::PosixLock() : attr_(), mutex_() { - pthread_mutexattr_init(&attr_); - pthread_mutexattr_settype(&attr_, PTHREAD_MUTEX_RECURSIVE); - - pthread_mutex_init(&mutex_, &attr_); -} - -PosixLock::~PosixLock() { - pthread_mutex_destroy(&mutex_); - - pthread_mutexattr_destroy(&attr_); -} - -void PosixLock::lock() { pthread_mutex_lock(&mutex_); } - -void PosixLock::unlock() { pthread_mutex_unlock(&mutex_); } - -} // namespace nearby -} // namespace location diff --git a/cpp/platform/impl/shared/posix_lock.h b/cpp/platform/impl/shared/posix_lock.h deleted file mode 100644 index b972e7e4..00000000 --- a/cpp/platform/impl/shared/posix_lock.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef PLATFORM_IMPL_SHARED_POSIX_LOCK_H_ -#define PLATFORM_IMPL_SHARED_POSIX_LOCK_H_ - -#include - -#include "platform/api/lock.h" - -namespace location { -namespace nearby { - -class PosixLock : public Lock { - public: - PosixLock(); - ~PosixLock() override; - - void lock() override; - void unlock() override; - - private: - friend class PosixConditionVariable; - - pthread_mutexattr_t attr_; - pthread_mutex_t mutex_; -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_IMPL_SHARED_POSIX_LOCK_H_ diff --git a/cpp/platform_v2/impl/shared/posix_mutex.cc b/cpp/platform/impl/shared/posix_mutex.cc similarity index 91% rename from cpp/platform_v2/impl/shared/posix_mutex.cc rename to cpp/platform/impl/shared/posix_mutex.cc index 65cdc917..6e6588a3 100644 --- a/cpp/platform_v2/impl/shared/posix_mutex.cc +++ b/cpp/platform/impl/shared/posix_mutex.cc @@ -1,4 +1,4 @@ -#include "platform_v2/impl/shared/posix_mutex.h" +#include "platform/impl/shared/posix_mutex.h" namespace location { namespace nearby { diff --git a/cpp/platform_v2/impl/shared/posix_mutex.h b/cpp/platform/impl/shared/posix_mutex.h similarity index 71% rename from cpp/platform_v2/impl/shared/posix_mutex.h rename to cpp/platform/impl/shared/posix_mutex.h index 01b2e1f2..223f144e 100644 --- a/cpp/platform_v2/impl/shared/posix_mutex.h +++ b/cpp/platform/impl/shared/posix_mutex.h @@ -1,9 +1,9 @@ -#ifndef PLATFORM_V2_IMPL_SHARED_POSIX_MUTEX_H_ -#define PLATFORM_V2_IMPL_SHARED_POSIX_MUTEX_H_ +#ifndef PLATFORM_IMPL_SHARED_POSIX_MUTEX_H_ +#define PLATFORM_IMPL_SHARED_POSIX_MUTEX_H_ #include -#include "platform_v2/api/mutex.h" +#include "platform/api/mutex.h" namespace location { namespace nearby { @@ -28,4 +28,4 @@ class ABSL_LOCKABLE Mutex : public api::Mutex { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_IMPL_SHARED_POSIX_MUTEX_H_ +#endif // PLATFORM_IMPL_SHARED_POSIX_MUTEX_H_ diff --git a/cpp/platform/impl/shared/sample/BUILD b/cpp/platform/impl/shared/sample/BUILD deleted file mode 100644 index 0a29de7d..00000000 --- a/cpp/platform/impl/shared/sample/BUILD +++ /dev/null @@ -1,21 +0,0 @@ -cc_library( - name = "sample_wifi_medium", - srcs = [ - "sample_wifi_medium.cc", - ], - hdrs = [ - "sample_wifi_medium.h", - ], - visibility = [ - "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", - "//core:__subpackages__", - "//platform/impl:__subpackages__", - ], - deps = [ - "//platform:types", - "//platform:utils", - "//platform/api", - "//platform/port:string", - "//absl/time", - ], -) diff --git a/cpp/platform/impl/shared/sample/sample_wifi_medium.cc b/cpp/platform/impl/shared/sample/sample_wifi_medium.cc deleted file mode 100644 index fed3d1fc..00000000 --- a/cpp/platform/impl/shared/sample/sample_wifi_medium.cc +++ /dev/null @@ -1,110 +0,0 @@ -#include "platform/impl/shared/sample/sample_wifi_medium.h" - -#include - -#include "platform/prng.h" -#include "absl/time/clock.h" -#include "absl/time/time.h" - -namespace location { -namespace nearby { -namespace sample { - -namespace { - -const char* kOpenSSID = "__OPEN__"; -const char* kWpaPskSSID = "__WPA_PSK__"; -const char* kWepSSID = "__WEP__"; -const char* kNoInternetConnectivitySSID = "__NO_INTERNET_CONNECTIVITY__"; -const char* kConnectionFailureSSID = "__CONNECTION_FAILURE__"; -const char* kAuthFailureSSID = "__AUTH_FAILURE__"; - -std::uint32_t boundedUInt32(std::uint32_t upper_limit) { - return Prng().nextUInt32() % (upper_limit + 1); -} - -void randomSleep(std::uint32_t upper_limit_millis) { - absl::SleepFor(absl::Milliseconds(boundedUInt32(upper_limit_millis))); -} - -} // namespace - -std::vector SampleWifiMedium::canned_scan_results_; - -SampleWifiMedium::SampleWifiMedium() : current_ssid_() { - // One-time initialization of our static canned_scan_results_. - if (canned_scan_results_.empty()) { - canned_scan_results_.push_back( - SampleWifiScanResult(kOpenSSID, 1, 2401, WifiAuthType::OPEN)); - canned_scan_results_.push_back( - SampleWifiScanResult(kWpaPskSSID, 2, 5002, WifiAuthType::WPA_PSK)); - canned_scan_results_.push_back( - SampleWifiScanResult(kWepSSID, 3, 2403, WifiAuthType::WEP)); - canned_scan_results_.push_back(SampleWifiScanResult( - kNoInternetConnectivitySSID, 4, 5004, WifiAuthType::OPEN)); - canned_scan_results_.push_back(SampleWifiScanResult( - kConnectionFailureSSID, 5, 2405, WifiAuthType::OPEN)); - canned_scan_results_.push_back( - SampleWifiScanResult(kAuthFailureSSID, 6, 5006, WifiAuthType::OPEN)); - } -} - -SampleWifiMedium::~SampleWifiMedium() {} - -bool SampleWifiMedium::scan( - Ptr scan_result_callback) { - // Sleep for up to 10 seconds, to simulate performing an actual Wifi scan. - randomSleep(10 * 1000); - - // Construct the response. - std::vector > scan_results; - for (std::vector::const_iterator it = - canned_scan_results_.begin(); - it != canned_scan_results_.end(); it++) { - scan_results.push_back(ConstPtr( - new SampleWifiScanResult(it->getSSID(), it->getSignalStrengthDbm(), - it->getFrequencyMhz(), it->getAuthType()))); - } - - // And report it back. - scan_result_callback->onScanResults(scan_results); - - return false; -} - -WifiConnectionStatus::Value SampleWifiMedium::connectToNetwork( - const std::string& ssid, const std::string& password, - WifiAuthType::Value auth_type) { - // Sleep for up to 10 seconds, to simulate actually connecting to the SSID. - randomSleep(10 * 1000); - - if (kConnectionFailureSSID == ssid) { - return WifiConnectionStatus::CONNECTION_FAILURE; - } - - if (kAuthFailureSSID == ssid) { - return WifiConnectionStatus::AUTH_FAILURE; - } - - return WifiConnectionStatus::CONNECTED; -} - -bool SampleWifiMedium::verifyInternetConnectivity() { - if (current_ssid_.empty()) { - return false; - } - - // Sleep for up to 5 seconds, to simulate actually verifying internet - // connectivity. - randomSleep(5 * 1000); - - return current_ssid_ != kNoInternetConnectivitySSID; -} - -std::string SampleWifiMedium::getIPAddress() { - return current_ssid_.empty() ? "" : "1.2.3.4"; -} - -} // namespace sample -} // namespace nearby -} // namespace location diff --git a/cpp/platform/impl/shared/sample/sample_wifi_medium.h b/cpp/platform/impl/shared/sample/sample_wifi_medium.h deleted file mode 100644 index 688ea2d2..00000000 --- a/cpp/platform/impl/shared/sample/sample_wifi_medium.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef PLATFORM_IMPL_SHARED_SAMPLE_SAMPLE_WIFI_MEDIUM_H_ -#define PLATFORM_IMPL_SHARED_SAMPLE_SAMPLE_WIFI_MEDIUM_H_ - -#include "platform/api/wifi.h" - -namespace location { -namespace nearby { -namespace sample { - -class SampleWifiScanResult : public WifiScanResult { - public: - SampleWifiScanResult(const std::string& ssid, - std::int32_t signal_strength_dbm, - std::int32_t frequency_mhz, - WifiAuthType::Value auth_type) - : ssid_(ssid), - signal_strength_dbm_(signal_strength_dbm), - frequency_mhz_(frequency_mhz), - auth_type_(auth_type) {} - ~SampleWifiScanResult() override {} - - std::string getSSID() const override { return ssid_; } - std::int32_t getSignalStrengthDbm() const override { - return signal_strength_dbm_; - } - std::int32_t getFrequencyMhz() const override { return frequency_mhz_; } - WifiAuthType::Value getAuthType() const override { return auth_type_; } - - private: - const std::string ssid_; - const std::int32_t signal_strength_dbm_; - const std::int32_t frequency_mhz_; - const WifiAuthType::Value auth_type_; -}; - -class SampleWifiMedium : public WifiMedium { - public: - SampleWifiMedium(); - ~SampleWifiMedium() override; - - bool scan(Ptr scan_result_callback) override; - WifiConnectionStatus::Value connectToNetwork( - const std::string& ssid, const std::string& password, - WifiAuthType::Value auth_type) override; - bool verifyInternetConnectivity() override; - std::string getIPAddress() override; - - private: - static std::vector canned_scan_results_; - - // The SSID this Wifi stack is currently connected to; empty string if none. - std::string current_ssid_; -}; - -} // namespace sample -} // namespace nearby -} // namespace location - -#endif // PLATFORM_IMPL_SHARED_SAMPLE_SAMPLE_WIFI_MEDIUM_H_ diff --git a/cpp/platform/logging.h b/cpp/platform/logging.h deleted file mode 100644 index 836ce62f..00000000 --- a/cpp/platform/logging.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef PLATFORM_LOGGING_H_ -#define PLATFORM_LOGGING_H_ - -#include "absl/base/internal/raw_logging.h" - -namespace location { -namespace nearby { - -// This uses an explicit printf-format and arguments list, and supports the -// following severities: -// -// - INFO -// - WARNING -// - ERROR -// - FATAL -// -// To make it easy to filer while debugging, it prepends "[NEARBY] " to all its -// logged messages. -// -// Sample usage: -// -// NEARBY_LOG(INFO, "%d is an int and %s is a std::string", i, s.c_str()); -#define NEARBY_LOG(severity, ...) \ - ABSL_RAW_LOG(severity, "[NEARBY] " __VA_ARGS__) - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_LOGGING_H_ diff --git a/cpp/platform/pipe.cc b/cpp/platform/pipe.cc deleted file mode 100644 index 0cb6818c..00000000 --- a/cpp/platform/pipe.cc +++ /dev/null @@ -1,188 +0,0 @@ -#include "platform/pipe.h" - -#include "platform/api/platform.h" -#include "platform/synchronized.h" - -namespace location { -namespace nearby { - -namespace { -using Platform = platform::ImplementationPlatform; -} - -namespace pipe { - -class PipeInputStream : public InputStream { - public: - explicit PipeInputStream(Ptr pipe) : pipe_(pipe) {} - ~PipeInputStream() override { close(); } - ExceptionOr> read() override { return read(kChunkSize); } - - ExceptionOr> read(std::int64_t size) override { - return pipe_->read(size); - } - - Exception::Value close() override { - pipe_->markInputStreamClosed(); - - return Exception::NONE; - } - - private: - static constexpr std::int64_t kChunkSize = 64 * 1024; - - Ptr pipe_; -}; - -class PipeOutputStream : public OutputStream { - public: - explicit PipeOutputStream(Ptr pipe) : pipe_(pipe) {} - ~PipeOutputStream() override { close(); } - - Exception::Value write(ConstPtr data) override { - // Avoid leaks. - ScopedPtr> scoped_data(data); - - return pipe_->write(scoped_data.release()); - } - - Exception::Value flush() override { - // No-op. - return Exception::NONE; - } - - Exception::Value close() override { - pipe_->markOutputStreamClosed(); - - return Exception::NONE; - } - - private: - Ptr pipe_; -}; - -} // namespace pipe - -Pipe::Pipe() - : lock_(Platform::createLock()), - cond_(Platform::createConditionVariable(lock_.get())), - buffer_(), - input_stream_closed_(false), - output_stream_closed_(false), - read_all_chunks_(false) {} - -Pipe::~Pipe() { - // Deallocate all the chunks still left in buffer_. - for (BufferType::iterator chunk_iter = buffer_.begin(); - chunk_iter != buffer_.end(); ++chunk_iter) { - (*chunk_iter).destroy(); - } -} - -Ptr Pipe::createInputStream(Ptr self) { - assert(self.isRefCounted()); - return MakeRefCountedPtr(new pipe::PipeInputStream(self)); -} - -Ptr Pipe::createOutputStream(Ptr self) { - assert(self.isRefCounted()); - return MakeRefCountedPtr(new pipe::PipeOutputStream(self)); -} - -ExceptionOr> Pipe::read(std::int64_t size) { - Synchronized s(lock_.get()); - - // We're done reading all the chunks that were written before the OutputStream - // was closed, so there's nothing to do here other than return an empty chunk - // to serve as an EOF indication to callers. - if (read_all_chunks_) { - ExceptionOr>(ConstPtr()); - } - - while (buffer_.empty() && !input_stream_closed_) { - Exception::Value wait_exception = cond_->wait(); - - if (Exception::NONE != wait_exception) { - if (Exception::INTERRUPTED == wait_exception) { - return ExceptionOr>(Exception::IO); - } - } - } - - if (input_stream_closed_) { - return ExceptionOr>(Exception::IO); - } - - ScopedPtr> first_chunk(buffer_.front()); - buffer_.pop_front(); - - // If we received our sentinel chunk, mark the fact that there cannot - // possibly be any more chunks to read here on in, and return an empty chunk - // to serve as an EOF indication to callers. - if (first_chunk.isNull()) { - read_all_chunks_ = true; - return ExceptionOr>(ConstPtr()); - } - - // If first_chunk is small enough to not overshoot the requested 'size', just - // return that. - if (first_chunk->size() <= size) { - return ExceptionOr>(first_chunk.release()); - } else { - // Break first_chunk into 2 parts -- the first one of which (next_chunk) - // will be 'size' bytes long, and will be returned, and the second one of - // which (overflow_chunk) will be re-inserted into buffer_, at the head of - // the queue, to be served up in the next call to read(). - ScopedPtr> next_chunk( - MakeConstPtr(new ByteArray(first_chunk->getData(), size))); - ScopedPtr> overflow_chunk(MakeConstPtr(new ByteArray( - first_chunk->getData() + size, first_chunk->size() - size))); - buffer_.push_front(overflow_chunk.release()); - return ExceptionOr>(next_chunk.release()); - } -} - -Exception::Value Pipe::write(ConstPtr data) { - Synchronized s(lock_.get()); - - return writeLocked(data); -} - -void Pipe::markInputStreamClosed() { - Synchronized s(lock_.get()); - - input_stream_closed_ = true; - // Trigger cond_ to unblock a potentially-blocked call to read(), and to let - // it know to return Exception::IO. - cond_->notify(); -} - -void Pipe::markOutputStreamClosed() { - Synchronized s(lock_.get()); - - // Write a sentinel null chunk before marking output_stream_closed as true. - writeLocked(ConstPtr()); - output_stream_closed_ = true; -} - -Exception::Value Pipe::writeLocked(ConstPtr data) { - // Avoid leaks. - ScopedPtr> scoped_data(data); - - if (eitherStreamClosed()) { - return Exception::IO; - } - - buffer_.push_back(scoped_data.release()); - // Trigger cond_ to unblock a potentially-blocked call to read(), now that - // there's more data for it to consume. - cond_->notify(); - return Exception::NONE; -} - -bool Pipe::eitherStreamClosed() const { - return input_stream_closed_ || output_stream_closed_; -} - -} // namespace nearby -} // namespace location diff --git a/cpp/platform/pipe.h b/cpp/platform/pipe.h deleted file mode 100644 index 4242f845..00000000 --- a/cpp/platform/pipe.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef PLATFORM_PIPE_H_ -#define PLATFORM_PIPE_H_ - -#include -#include - -#include "platform/api/condition_variable.h" -#include "platform/api/input_stream.h" -#include "platform/api/lock.h" -#include "platform/api/output_stream.h" -#include "platform/byte_array.h" -#include "platform/exception.h" -#include "platform/ptr.h" - -namespace location { -namespace nearby { - -namespace pipe { - -class PipeInputStream; -class PipeOutputStream; - -} // namespace pipe - -class Pipe { - public: - Pipe(); - ~Pipe(); - - // The returned InputStream is auto-destroyed when no longer referenced. - static Ptr createInputStream(Ptr); - // The returned OutputStream is auto-destroyed when no longer referenced. - static Ptr createOutputStream(Ptr); - - private: - ////////////////////////////////////////////////////////////////////////////// - // Everything in this first private: section is only used by PipeInputStream - // and PipeOutputStream, thus forming the interface presented to those 2 - // classes. - ////////////////////////////////////////////////////////////////////////////// - - friend class pipe::PipeInputStream; - friend class pipe::PipeOutputStream; - - ExceptionOr > read(std::int64_t size); - Exception::Value write(ConstPtr data); - - void markInputStreamClosed(); - void markOutputStreamClosed(); - - private: - Exception::Value writeLocked(ConstPtr data); - - bool eitherStreamClosed() const; - - ScopedPtr > lock_; - ScopedPtr > cond_; - typedef std::deque > BufferType; - BufferType buffer_; - bool input_stream_closed_; - bool output_stream_closed_; - bool read_all_chunks_; -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_PIPE_H_ diff --git a/cpp/platform/pipe_test.cc b/cpp/platform/pipe_test.cc deleted file mode 100644 index 8657b1c5..00000000 --- a/cpp/platform/pipe_test.cc +++ /dev/null @@ -1,397 +0,0 @@ -#include "platform/pipe.h" - -#include - -#include - -#include "platform/api/platform.h" -#include "platform/port/string.h" -#include "platform/prng.h" -#include "platform/ptr.h" -#include "platform/runnable.h" -#include "gtest/gtest.h" -#include "absl/time/time.h" - -namespace location { -namespace nearby { -namespace { - -using SamplePipe = Pipe; - -TEST(PipeTest, SimpleWriteRead) { - auto pipe = MakeRefCountedPtr(new SamplePipe()); - - ScopedPtr> input_stream(SamplePipe::createInputStream(pipe)); - ScopedPtr> output_stream( - SamplePipe::createOutputStream(pipe)); - - std::string data("ABCD"); - ASSERT_EQ(Exception::NONE, output_stream->write(MakeConstPtr( - new ByteArray(data.data(), data.size())))); - - ExceptionOr> read_data = input_stream->read(); - ASSERT_TRUE(read_data.ok()); - ScopedPtr> scoped_read_data(read_data.result()); - ASSERT_EQ(data.size(), scoped_read_data->size()); - ASSERT_EQ(0, memcmp(data.data(), scoped_read_data->getData(), - scoped_read_data->size())); -} - -TEST(PipeTest, WriteEndClosedBeforeRead) { - auto pipe = MakeRefCountedPtr(new SamplePipe()); - - ScopedPtr> input_stream(SamplePipe::createInputStream(pipe)); - ScopedPtr> output_stream( - SamplePipe::createOutputStream(pipe)); - - std::string data("ABCD"); - ASSERT_EQ(Exception::NONE, output_stream->write(MakeConstPtr( - new ByteArray(data.data(), data.size())))); - - // Close the write end before the read end has even begun reading. - ASSERT_EQ(Exception::NONE, output_stream->close()); - - // We should still be able to read what was written. - ExceptionOr> read_data = input_stream->read(); - ASSERT_TRUE(read_data.ok()); - ScopedPtr> scoped_read_data(read_data.result()); - ASSERT_EQ(data.size(), scoped_read_data->size()); - ASSERT_EQ(0, memcmp(data.data(), scoped_read_data->getData(), - scoped_read_data->size())); - - // And after that, we should get our indication that all the data that could - // ever be read, has already been read. - read_data = input_stream->read(); - ASSERT_TRUE(read_data.ok()); - ASSERT_TRUE(read_data.result().isNull()); -} - -TEST(PipeTest, ReadEndClosedBeforeWrite) { - auto pipe = MakeRefCountedPtr(new SamplePipe()); - - ScopedPtr> input_stream(SamplePipe::createInputStream(pipe)); - ScopedPtr> output_stream( - SamplePipe::createOutputStream(pipe)); - - // Close the read end before the write end has even begun writing. - ASSERT_EQ(Exception::NONE, input_stream->close()); - - std::string data("ABCD"); - ASSERT_EQ(Exception::IO, output_stream->write(MakeConstPtr( - new ByteArray(data.data(), data.size())))); -} - -TEST(PipeTest, SizedReadMoreThanFirstChunkSize) { - auto pipe = MakeRefCountedPtr(new SamplePipe()); - - ScopedPtr> input_stream(SamplePipe::createInputStream(pipe)); - ScopedPtr> output_stream( - SamplePipe::createOutputStream(pipe)); - - std::string data("ABCD"); - ASSERT_EQ(Exception::NONE, output_stream->write(MakeConstPtr( - new ByteArray(data.data(), data.size())))); - - // Even though we ask for double of what's there in the first chunk, we should - // get back only what's there in that first chunk, and that's alright. - ExceptionOr> read_data = - input_stream->read(data.size() * 2); - ASSERT_TRUE(read_data.ok()); - ScopedPtr> scoped_read_data(read_data.result()); - ASSERT_EQ(data.size(), scoped_read_data->size()); - ASSERT_EQ(0, memcmp(data.data(), scoped_read_data->getData(), - scoped_read_data->size())); -} - -TEST(PipeTest, SizedReadLessThanFirstChunkSize) { - auto pipe = MakeRefCountedPtr(new SamplePipe()); - - ScopedPtr> input_stream(SamplePipe::createInputStream(pipe)); - ScopedPtr> output_stream( - SamplePipe::createOutputStream(pipe)); - - // Compose 'data' of 2 parts, to make it easier to validate our expectations. - std::string data_first_part("ABCD"); - std::string data_second_part("EFGHIJ"); - std::string data = data_first_part + data_second_part; - ASSERT_EQ(Exception::NONE, output_stream->write(MakeConstPtr( - new ByteArray(data.data(), data.size())))); - - // When we ask for less than what's there in the first chunk, we should get - // back exactly what we asked for, with the remainder still being available - // for the next read. - std::int64_t desired_size = data_first_part.size(); - ExceptionOr> first_read_data = - input_stream->read(desired_size); - ASSERT_TRUE(first_read_data.ok()); - ScopedPtr> scoped_first_read_data( - first_read_data.result()); - ASSERT_EQ(desired_size, scoped_first_read_data->size()); - ASSERT_EQ(0, memcmp(data_first_part.data(), scoped_first_read_data->getData(), - scoped_first_read_data->size())); - - // Now read the remainder, and get everything that ought to have been left. - std::int64_t remaining_size = data_second_part.size(); - ExceptionOr> second_read_data = input_stream->read(); - ASSERT_TRUE(second_read_data.ok()); - ScopedPtr> scoped_second_read_data( - second_read_data.result()); - ASSERT_EQ(remaining_size, scoped_second_read_data->size()); - ASSERT_EQ(0, - memcmp(data_second_part.data(), scoped_second_read_data->getData(), - scoped_second_read_data->size())); -} - -TEST(PipeTest, ReadAfterInputStreamClosed) { - auto pipe = MakeRefCountedPtr(new SamplePipe()); - - ScopedPtr> input_stream(SamplePipe::createInputStream(pipe)); - ScopedPtr> output_stream( - SamplePipe::createOutputStream(pipe)); - - input_stream->close(); - - ExceptionOr> read_data = input_stream->read(); - ASSERT_TRUE(!read_data.ok()); - ASSERT_EQ(Exception::IO, read_data.exception()); -} - -TEST(PipeTest, WriteAfterOutputStreamClosed) { - auto pipe = MakeRefCountedPtr(new SamplePipe()); - - ScopedPtr> input_stream(SamplePipe::createInputStream(pipe)); - ScopedPtr> output_stream( - SamplePipe::createOutputStream(pipe)); - - output_stream->close(); - - std::string data("ABCD"); - ASSERT_EQ(Exception::IO, output_stream->write(MakeConstPtr( - new ByteArray(data.data(), data.size())))); -} - -TEST(PipeTest, RepeatedClose) { - auto pipe = MakeRefCountedPtr(new SamplePipe()); - - ScopedPtr> input_stream(SamplePipe::createInputStream(pipe)); - ScopedPtr> output_stream( - SamplePipe::createOutputStream(pipe)); - - ASSERT_EQ(Exception::NONE, output_stream->close()); - ASSERT_EQ(Exception::NONE, output_stream->close()); - ASSERT_EQ(Exception::NONE, output_stream->close()); - - ASSERT_EQ(Exception::NONE, input_stream->close()); - ASSERT_EQ(Exception::NONE, input_stream->close()); - ASSERT_EQ(Exception::NONE, input_stream->close()); -} - -class Thread { - public: - Thread() : thread_(), attr_(), runnable_() { - pthread_attr_init(&attr_); - pthread_attr_setdetachstate(&attr_, PTHREAD_CREATE_JOINABLE); - } - ~Thread() { pthread_attr_destroy(&attr_); } - - void start(Ptr runnable) { - runnable_ = runnable; - - pthread_create(&thread_, &attr_, Thread::body, this); - } - - void join() { - pthread_join(thread_, nullptr); - - runnable_.destroy(); - } - - private: - static void* body(void* args) { - reinterpret_cast(args)->runnable_->run(); - return nullptr; - } - - pthread_t thread_; - pthread_attr_t attr_; - Ptr runnable_; -}; - -TEST(PipeTest, ReadBlockedUntilWrite) { - typedef volatile bool CrossThreadBool; - - class ReaderRunnable : public Runnable { - public: - ReaderRunnable(Ptr input_stream, - const std::string& expected_read_data, - CrossThreadBool* ok_for_read_to_unblock) - : input_stream_(input_stream), - expected_read_data_(expected_read_data), - ok_for_read_to_unblock_(ok_for_read_to_unblock) {} - ~ReaderRunnable() override {} - - void run() override { - ExceptionOr> read_data = input_stream_->read(); - - // Make sure read() doesn't return before it's appropriate. - if (!*ok_for_read_to_unblock_) { - FAIL() << "read() unblocked before it was supposed to."; - } - - // And then run our normal set of checks to make sure the read() was - // successful. - ASSERT_TRUE(read_data.ok()); - ScopedPtr> scoped_read_data(read_data.result()); - ASSERT_EQ(expected_read_data_.size(), scoped_read_data->size()); - ASSERT_EQ(0, - memcmp(expected_read_data_.data(), scoped_read_data->getData(), - scoped_read_data->size())); - } - - private: - ScopedPtr> input_stream_; - const std::string& expected_read_data_; - CrossThreadBool* ok_for_read_to_unblock_; - }; - - auto pipe = MakeRefCountedPtr(new SamplePipe()); - - ScopedPtr> output_stream( - SamplePipe::createOutputStream(pipe)); - - // State shared between this thread (the writer) and reader_thread. - CrossThreadBool ok_for_read_to_unblock = false; - std::string data("ABCD"); - - // Kick off reader_thread. - Thread reader_thread; - reader_thread.start(MakePtr(new ReaderRunnable( - SamplePipe::createInputStream(pipe), data, &ok_for_read_to_unblock))); - - // Introduce a delay before we actually write anything. - absl::SleepFor(absl::Seconds(5)); - // Mark that we're done with the delay, and that the write is about to occur - // (this is slightly earlier than it ought to be, but there's no way to - // atomically set this from within the implementation of write(), and doing it - // after is too late for the purposes of this test). - ok_for_read_to_unblock = true; - - // Perform the actual write. - ASSERT_EQ(Exception::NONE, output_stream->write(MakeConstPtr( - new ByteArray(data.data(), data.size())))); - - // And wait for reader_thread to finish. - reader_thread.join(); -} - -TEST(PipeTest, ConcurrentWriteAndRead) { - class BaseRunnable : public Runnable { - protected: - explicit BaseRunnable(const std::vector& chunks) - : chunks_(chunks), prng_() {} - ~BaseRunnable() override {} - - void randomSleep() { - // Generate a random sleep between 100 and 1000 milliseconds. - absl::SleepFor(absl::Milliseconds(boundedUInt32(100, 1000))); - } - - const std::vector& chunks_; - - private: - // Both ends of the bounds are inclusive. - std::uint32_t boundedUInt32(std::uint32_t lower_bound, - std::uint32_t upper_bound) { - return (prng_.nextUInt32() % (upper_bound - lower_bound + 1)) + - lower_bound; - } - - Prng prng_; - }; - - class WriterRunnable : public BaseRunnable { - public: - WriterRunnable(Ptr output_stream, - const std::vector& chunks) - : BaseRunnable(chunks), output_stream_(output_stream) {} - ~WriterRunnable() override {} - - void run() override { - for (std::vector::const_iterator it = chunks_.begin(); - it != chunks_.end(); ++it) { - const std::string& chunk = *it; - - randomSleep(); // Random pauses before each write. - ASSERT_EQ(Exception::NONE, - output_stream_->write( - MakeConstPtr(new ByteArray(chunk.data(), chunk.size())))); - } - - randomSleep(); // A random pause before closing the writer end. - ASSERT_EQ(Exception::NONE, output_stream_->close()); - } - - private: - ScopedPtr> output_stream_; - }; - - class ReaderRunnable : public BaseRunnable { - public: - ReaderRunnable(Ptr input_stream, - const std::vector& chunks) - : BaseRunnable(chunks), input_stream_(input_stream) {} - ~ReaderRunnable() override {} - - void run() override { - // First, calculate what we expect to receive, in total. - std::string expected_data; - for (std::vector::const_iterator it = chunks_.begin(); - it != chunks_.end(); ++it) { - expected_data += *it; - } - - // Then, start actually receiving. - std::string actual_data; - while (true) { - randomSleep(); // Random pauses before each read. - ExceptionOr> read_data = input_stream_->read(); - if (read_data.ok()) { - ScopedPtr> scoped_read_data(read_data.result()); - if (scoped_read_data.isNull()) { - break; // Normal exit from the read loop. - } - actual_data += std::string(scoped_read_data->getData(), - scoped_read_data->size()); - } else { - break; // Erroneous exit from the read loop. - } - } - - // And once we're done, check that we got everything we expected. - ASSERT_EQ(expected_data, actual_data); - } - - private: - ScopedPtr> input_stream_; - }; - - auto pipe = MakeRefCountedPtr(new SamplePipe()); - - std::vector chunks; - chunks.push_back("ABCD"); - chunks.push_back("EFGH"); - chunks.push_back("IJKL"); - - Thread writer_thread; - Thread reader_thread; - writer_thread.start(MakePtr( - new WriterRunnable(SamplePipe::createOutputStream(pipe), chunks))); - reader_thread.start( - MakePtr(new ReaderRunnable(SamplePipe::createInputStream(pipe), chunks))); - writer_thread.join(); - reader_thread.join(); -} - -} // namespace -} // namespace nearby -} // namespace location diff --git a/cpp/platform/port/BUILD b/cpp/platform/port/BUILD deleted file mode 100644 index 80447569..00000000 --- a/cpp/platform/port/BUILD +++ /dev/null @@ -1,38 +0,0 @@ -cc_library( - name = "config", - hdrs = [ - "config.h", - ], - visibility = [ - "//visibility:private", - ], -) - -cc_library( - name = "string", - hdrs = [ - "string.h", - ], - visibility = [ - "//core:__subpackages__", - "//platform:__subpackages__", - "//location/nearby/setup/core:__subpackages__", - ], - deps = [ - ":config", - ], -) - -cc_library( - name = "down_cast", - hdrs = [ - "down_cast.h", - ], - visibility = [ - "//core:__subpackages__", - "//platform:__subpackages__", - ], - deps = [ - ":config", - ], -) diff --git a/cpp/platform/port/down_cast.h b/cpp/platform/port/down_cast.h deleted file mode 100644 index 161884c8..00000000 --- a/cpp/platform/port/down_cast.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef PLATFORM_PORT_DOWN_CAST_H_ -#define PLATFORM_PORT_DOWN_CAST_H_ - -#include "platform/port/config.h" - -#if NEARBY_USE_RTTI -#define DOWN_CAST dynamic_cast -#else -#define DOWN_CAST static_cast -#endif - -#endif // PLATFORM_PORT_DOWN_CAST_H_ diff --git a/cpp/platform/port/string.h b/cpp/platform/port/string.h deleted file mode 100644 index d9a0cdff..00000000 --- a/cpp/platform/port/string.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef PLATFORM_PORT_STRING_H_ -#define PLATFORM_PORT_STRING_H_ - -#include - -#include "platform/port/config.h" - -#if NEARBY_USE_STD_STRING -using std::string; -#endif - -#endif // PLATFORM_PORT_STRING_H_ diff --git a/cpp/platform/prng.cc b/cpp/platform/prng.cc deleted file mode 100644 index 7f98870c..00000000 --- a/cpp/platform/prng.cc +++ /dev/null @@ -1,45 +0,0 @@ -#include "platform/prng.h" - -#include - -#include "absl/time/clock.h" - -namespace location { -namespace nearby { - -#define UNSIGNED_INT_BITMASK (std::numeric_limits::max()) - -Prng::Prng() { - // absl::GetCurrentTimeNanos() returns 64 bits, but srand() wants an unsigned - // int, so we may have to lose some of those 64 bits. - // - // The lower bits of the current-time-in-nanos are likely to have more entropy - // than the upper bits, so choose the former. - srand(static_cast(absl::GetCurrentTimeNanos() & - UNSIGNED_INT_BITMASK)); -} - -Prng::~Prng() { - // Nothing to do. -} - -#define RANDOM_BYTE (rand() & 0x0FF) // NOLINT - -std::int32_t Prng::nextInt32() { - return (static_cast(RANDOM_BYTE) << 24) | - (static_cast(RANDOM_BYTE) << 16) | - (static_cast(RANDOM_BYTE) << 8) | - (static_cast(RANDOM_BYTE)); -} - -std::uint32_t Prng::nextUInt32() { - return static_cast(nextInt32()); -} - -std::int64_t Prng::nextInt64() { - return (static_cast(nextInt32()) << 32) | - (static_cast(nextInt32())); -} - -} // namespace nearby -} // namespace location diff --git a/cpp/platform/prng.h b/cpp/platform/prng.h deleted file mode 100644 index 9a7ff34a..00000000 --- a/cpp/platform/prng.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef PLATFORM_PRNG_H_ -#define PLATFORM_PRNG_H_ - -#include - -namespace location { -namespace nearby { - -// A (non-cryptographic) pseudo-random number generator. -class Prng { - public: - Prng(); - ~Prng(); - - std::int32_t nextInt32(); - std::uint32_t nextUInt32(); - std::int64_t nextInt64(); -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_PRNG_H_ diff --git a/cpp/platform/prng_test.cc b/cpp/platform/prng_test.cc deleted file mode 100644 index e4115944..00000000 --- a/cpp/platform/prng_test.cc +++ /dev/null @@ -1,27 +0,0 @@ -#include "platform/prng.h" - -#include "gtest/gtest.h" - -namespace location { -namespace nearby { - -TEST(PrngTest, NextInt32) { - std::int32_t i = Prng().nextInt32(); - ASSERT_LE(i, std::numeric_limits::max()); - ASSERT_GE(i, std::numeric_limits::min()); -} - -TEST(PrngTest, NextUInt32) { - std::uint32_t i = Prng().nextUInt32(); - ASSERT_LE(i, std::numeric_limits::max()); - ASSERT_GE(i, std::numeric_limits::min()); -} - -TEST(PrngTest, NextInt64) { - std::int64_t i = Prng().nextInt64(); - ASSERT_LE(i, std::numeric_limits::max()); - ASSERT_GE(i, std::numeric_limits::min()); -} - -} // namespace nearby -} // namespace location diff --git a/cpp/platform/ptr.h b/cpp/platform/ptr.h deleted file mode 100644 index e675cac6..00000000 --- a/cpp/platform/ptr.h +++ /dev/null @@ -1,279 +0,0 @@ -#ifndef PLATFORM_PTR_H_ -#define PLATFORM_PTR_H_ - -#include -#include -#include -#include -#include - -#include "platform/logging.h" -#include "platform/port/down_cast.h" - -namespace location { -namespace nearby { - -// Forward declarations to make it possible for Ptr (a class template) to -// declare ConstifyPtr, DowncastPtr, and DowncastConstPtr (function templates) -// as friends. -// -// Note that the default template parameters to Ptr need to be defined here (at -// the first point of declaration), as opposed to at the actual definition of -// Ptr (which is what one might reasonably expect). -// -// See https://isocpp.org/wiki/faq/templates#template-friends for more. -template -class Ptr; -template -class ConstPtr; -template -ConstPtr ConstifyPtr(Ptr ptr); -template -Ptr DowncastPtr(Ptr base_ptr); -template -ConstPtr DowncastConstPtr(ConstPtr base_ptr); - -// A layer of indirection over a raw pointer. -// It is being deprecated in favor of standard c++ smart pointers. -// For transion period, Ptr will behave similar to shared_ptr. -// New code should use shrared_ptr or unique_ptr and not Ptr. -template -class Ptr { - public: - // Provide an alias for use as a dependent name. - typedef T PointeeType; - - Ptr() = default; - explicit Ptr(T* pointee) : ptr_(pointee) {} - Ptr(const Ptr& that) = default; - Ptr(Ptr&& that) = default; - - Ptr(std::shared_ptr ptr) : ptr_(ptr) {} // NOLINT - - template - Ptr& operator=(T2* ptr) { - Ptr tmp(ptr); - this->ptr_.swap(tmp); - return *this; - } - - Ptr& operator=(const Ptr& other) = default; - - // Conversion to Ptr, where T is trivially convertible to T2. E.g. - // conversion from derived to base class. - template - operator Ptr() { // NOLINT - return Ptr(std::static_pointer_cast(this->ptr_)); - } - operator Ptr() { // NOLINT - return Ptr(*this); - } - - explicit operator std::shared_ptr() { return this->ptr_; } - - ~Ptr() = default; - - bool operator==(const Ptr& other) const { - return *(this->ptr_) == *(other.ptr_); - } - bool operator!=(const Ptr& other) const { return !(*this == other); } - - bool operator<(const Ptr& other) const { - return *(this->ptr_) < *(other.ptr_); - } - - ABSL_DEPRECATED("Use c++ smart pointers directly instead of Ptr") - void destroy(bool = true) { - // Legacy code expects isNull() to return true after destroy(). - ptr_.reset(); - } - - ABSL_DEPRECATED("Use c++ smart pointers directly instead of Ptr") - void clear() { - // Legacy code expects isNull() to return true after clear(). - ptr_.reset(); - } - - T& operator*() const { return *ptr_; } - - T* operator->() const { return ptr_.get(); } - T* get() { return ptr_.get(); } - T* get() const { return ptr_.get(); } - void reset() { return ptr_.reset(); } - - ABSL_DEPRECATED("Use c++ smart pointers directly instead of Ptr") - bool isNull() const { return !this->ptr_; } - - // used by pipe.cc; introduced by cr/295271652 - ABSL_DEPRECATED("Use c++ smart pointers directly instead of Ptr") - bool isRefCounted() const { return true; } - - private: - template - friend ConstPtr ConstifyPtr(Ptr ptr); - template - friend Ptr DowncastPtr(Ptr base_ptr); - template - friend ConstPtr DowncastConstPtr(ConstPtr base_ptr); - - std::shared_ptr ptr_; -}; - -// Convenience wrapper for a read-only version of Ptr (in which the pointee -// cannot be modified). -// -// The C++11 equivalent would be: -// -// using ConstPtr = Ptr; -// -// Thus, -// -// Ptr x1(new X(...)); -// -// allows the underlying X instance to be modified, whereas -// -// ConstPtr x2(new X(...)); -// -// disallows that. -template -class ConstPtr : public Ptr { - public: - ConstPtr() {} - explicit ConstPtr(const T* pointee) : Ptr(pointee) {} - explicit ConstPtr(T* pointee) : Ptr(pointee) {} - explicit ConstPtr(Ptr ptr) : Ptr(ptr) {} -}; - -// RAII wrapper over Ptr and ConstPtr (hereon referred to by the PtrType -// placeholder), to allow for guarantees that the wrapped PtrType will be -// automatically destroyed when this wrapper object goes out of scope. -// -// Any class that has a PtrType member that it owns (and thus needs to invoke -// destroy() on) should wrap that PtrType in a ScopedPtr object. -// -// Similarly, any method that manipulates a (likely local) PtrType variable -// that needs to be destroy()ed at the end of that method should wrap that -// PtrType variable in a ScopedPtr object. -// -// Sample usage: -// -// Ptr x1(new X(...)); -// ScopedPtr > sx1(x1); -// -// ConstPtr x2(new X(...)); -// ScopedPtr > sx2(x2); -// -// ScopedPtr > sx3(new X(...)); -// -// ScopedPtr > sx4(new X(...)); -template -class ScopedPtr { - public: - explicit ScopedPtr(typename PtrType::PointeeType* pointee) : ptr_(pointee) {} - explicit ScopedPtr(PtrType ptr) : ptr_(ptr) {} - ScopedPtr(const ScopedPtr&) = delete; - ~ScopedPtr() = default; - - ScopedPtr& operator=(const ScopedPtr&) = delete; - - // Shadow methods for the underlying Ptr. - typename PtrType::PointeeType& operator*() const { return *ptr_; } - typename PtrType::PointeeType* operator->() const { - return ptr_.operator->(); - } - bool isNull() const { return ptr_.isNull(); } - - // Accessor for the underlying Ptr. - PtrType get() const { return this->ptr_; } - - // TODO(b/149938110): remove this completely. - PtrType release() { - // Legacy code expects isNull() to return true after release(). - PtrType ptr = std::move(ptr_); - ptr_.clear(); - return ptr; - } - - private: - PtrType ptr_; -}; - -// Utility function to create Ptr objects with less template-y noise by -// leveraging template argument deduction, in the same vein as std::make_pair(). -// -// Helps convert -// -// Ptr >(new MyRichType()); -// -// to -// -// MakePtr(new MyRichType()); -template -Ptr MakePtr(T* raw_ptr) { - return Ptr(raw_ptr); -} - -// Like MakePtr(), utility function to create ConstPtr objects with less -// template-y noise. -template -ConstPtr MakeConstPtr(T* raw_ptr) { - return ConstPtr(raw_ptr); -} - -// Used to create Ptr instances that are reference-counted (for when the -// lifetime and/or ownership of the pointee is not deterministic, like when a -// cache gives out handles to its cached objects to multiple threads to manage -// independently). -// -// Needless to say, the reference-counted-ness of these Ptr instances propagates -// across all copies and assignments, and as one might expect, the underlying -// pointee is deallocated when the reference count goes to 0. -// -// That implies that it's not strictly necessary to wrap these in ScopedPtrs -// (but it's perfectly fine to do so, and is even recommended, so readers of -// your code get a better understanding of the ownership story for each -// reference). -template -Ptr MakeRefCountedPtr(T* raw_ptr) { - return Ptr(raw_ptr); -} - -// ConstPtr counterpart to MakeRefCountedPtr(). -template -ConstPtr MakeRefCountedConstPtr(T* raw_ptr) { - return ConstPtr(raw_ptr); -} - -// Use this function to convert a Ptr object to a ConstPtr object. -template -ConstPtr ConstifyPtr(Ptr ptr) { - return ConstPtr(ptr); -} - -// Use this function to downcast from a Ptr to a Ptr. -// -// Because BaseT can be automatically deduced based on the base_ptr that's -// passed in, invocations of this method only need to explicitly specify ChildT, -// like so: -// -// Ptr my_child_ptr = DowncastPtr(my_base_ptr); -template -Ptr DowncastPtr(Ptr base_ptr) { - static_assert(std::is_base_of::value, - "Types do not share base class."); - return Ptr(std::static_pointer_cast(base_ptr.ptr_)); -} - -// ConstPtr counterpart to DowncastPtr(). -template -ConstPtr DowncastConstPtr(ConstPtr base_ptr) { - static_assert(std::is_base_of::value, - "Types do not share base class."); - return ConstPtr( - std::static_pointer_cast(base_ptr.ptr_)); -} - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_PTR_H_ diff --git a/cpp/platform/ptr_test.cc b/cpp/platform/ptr_test.cc deleted file mode 100644 index 622c4a60..00000000 --- a/cpp/platform/ptr_test.cc +++ /dev/null @@ -1,164 +0,0 @@ -#include "platform/ptr.h" - -#include "gtest/gtest.h" - -namespace location { -namespace nearby { - -TEST(PtrTest, RefCountedPtr_SingleReference) { - Ptr ref_counted = MakeRefCountedPtr(new int(1234)); - - // We just want to make sure that this test doesn't lead to a leak. - SUCCEED(); -} - -TEST(PtrTest, RefCountedPtr_MultipleReferences) { - Ptr ref_counted_1 = MakeRefCountedPtr(new int(1234)); - Ptr ref_counted_2 = ref_counted_1; - Ptr ref_counted_3(ref_counted_2); - - // We just want to make sure that this test doesn't lead to a leak, nor to - // double-deletion. - SUCCEED(); -} - -TEST(PtrTest, RefCountedPtr_MultipleReferencesWithScoped) { - Ptr ref_counted = MakeRefCountedPtr(new int(1234)); - ScopedPtr > scoped_ref_counted_1(ref_counted); - ScopedPtr > scoped_ref_counted_2(ref_counted); - - // We just want to make sure that this test doesn't lead to a leak, nor to - // double-deletion. - SUCCEED(); -} - -TEST(PtrTest, AssignmentOperator_RefCountedToRefCounted) { - Ptr ref_counted_1 = MakeRefCountedPtr(new int(1234)); - Ptr ref_counted_2 = MakeRefCountedPtr(new int(5678)); - - ref_counted_2 = ref_counted_1; - - ASSERT_EQ(1234, *ref_counted_1); - ASSERT_EQ(1234, *ref_counted_2); -} - -TEST(PtrTest, AssignmentOperator_SelfAssignment_RefCounted) { - Ptr ref_counted_1 = MakeRefCountedPtr(new int(1234)); - Ptr ref_counted_2(ref_counted_1); - - ref_counted_1 = ref_counted_2; - - ASSERT_EQ(1234, *ref_counted_1); - ASSERT_EQ(1234, *ref_counted_2); -} - -TEST(PtrTest, EqualityOperator_RefCounted) { - Ptr ref_counted_1 = MakeRefCountedPtr(new int(1234)); - Ptr ref_counted_2(ref_counted_1); - - ASSERT_TRUE(ref_counted_1 == ref_counted_2); - - ref_counted_1 = ref_counted_2; - - ASSERT_TRUE(ref_counted_1 == ref_counted_2); -} - -namespace { - -class Base { - public: - virtual ~Base() {} - - virtual int getInt() const = 0; -}; - -class Derived : public Base { - public: - explicit Derived(int i) : i_(i) {} - ~Derived() override {} - - int getInt() const override { return i_; } - - private: - const int i_; -}; - -} // namespace - -TEST(PtrTest, DerivedToBaseConversion_RefCounted) { - Ptr derived = MakeRefCountedPtr(new Derived(1234)); - Ptr base = derived; - - ASSERT_EQ(1234, derived->getInt()); - derived.destroy(); - // Additionally, make sure that 'base' is valid even after 'derived' has been - // destroyed. - ASSERT_EQ(1234, base->getInt()); -} - -TEST(PtrTest, DistinctValuesAreNotEqual) { - Ptr value1 = MakePtr(new int(5)); - Ptr value2 = MakePtr(new int(6)); - - ASSERT_NE(value1, value2); -} - -TEST(PtrTest, SameValuesAreEqual) { - Ptr value1 = MakePtr(new int(5)); - Ptr value2 = MakePtr(new int(5)); - - ASSERT_EQ(value1, value2); -} - -TEST(PtrTest, ScopedPtr_Release_RefCounted) { - Ptr ref_counted_1 = MakeRefCountedPtr(new int(1234)); - ScopedPtr > scoped_ref_counted_1(ref_counted_1); - - Ptr ref_counted_2 = scoped_ref_counted_1.release(); - - ASSERT_TRUE(scoped_ref_counted_1.isNull()); - ASSERT_EQ(1234, *ref_counted_1); - ASSERT_EQ(1234, *ref_counted_2); -} - -TEST(PtrTest, ScopedPtr_Release_RefCounted_Stay_Valid) { - Ptr ref_counted_1 = MakeRefCountedPtr(new int(1234)); - Ptr ref_counted_2 = ref_counted_1; - ScopedPtr > scoped_ref_counted_1(ref_counted_1); - - Ptr ref_counted_3 = scoped_ref_counted_1.release(); - - ASSERT_TRUE(scoped_ref_counted_1.isNull()); - ASSERT_EQ(1234, *ref_counted_2); - ASSERT_EQ(1234, *ref_counted_3); -} - -TEST(PtrTest, ConstifyPtr_RefCounted) { - Ptr ref_counted = MakeRefCountedPtr(new int(1234)); - - ConstPtr const_ref_counted = ConstifyPtr(ref_counted); - - ASSERT_EQ(1234, *ref_counted); - ref_counted.destroy(); - // Additionally, make sure that const_ref_counted is valid even after - // ref_counted has been destroyed. - ASSERT_EQ(1234, *const_ref_counted); -} - -TEST(PtrTest, DowncastPtr_RefCounted) { - Ptr derived = MakeRefCountedPtr(new Derived(1234)); - Ptr base = derived; - - Ptr derived_from_downcast = DowncastPtr(base); - - ASSERT_EQ(1234, base->getInt()); - base.destroy(); - ASSERT_EQ(1234, derived->getInt()); - derived.destroy(); - // Additionally, make sure that derived_from_downcast is valid even after - // derived has been destroyed. - ASSERT_EQ(1234, derived_from_downcast->getInt()); -} - -} // namespace nearby -} // namespace location diff --git a/cpp/platform/public/BUILD b/cpp/platform/public/BUILD new file mode 100644 index 00000000..4562f961 --- /dev/null +++ b/cpp/platform/public/BUILD @@ -0,0 +1,128 @@ +cc_library( + name = "types", + srcs = [ + "pipe.cc", + ], + hdrs = [ + "atomic_boolean.h", + "atomic_reference.h", + "cancelable.h", + "cancelable_alarm.h", + "condition_variable.h", + "count_down_latch.h", + "crypto.h", + "file.h", + "future.h", + "logging.h", + "multi_thread_executor.h", + "mutex.h", + "mutex_lock.h", + "pipe.h", + "scheduled_executor.h", + "settable_future.h", + "single_thread_executor.h", + "submittable_executor.h", + "system_clock.h", + ], + visibility = [ + "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", + "//core:__subpackages__", + "//platform/base:__pkg__", + "//platform/public:__pkg__", + ], + deps = [ + ":logging", + "//platform/api:platform", + "//platform/api:types", + "//platform/base", + "//platform/base:logging", + "//platform/base:util", + "//absl/base:core_headers", + "//absl/container:flat_hash_map", + "//absl/time", + ], +) + +cc_library( + name = "comm", + srcs = [ + "ble.cc", + "bluetooth_classic.cc", + "wifi_lan.cc", + ], + hdrs = [ + "ble.h", + "bluetooth_adapter.h", + "bluetooth_classic.h", + "webrtc.h", + "wifi_lan.h", + ], + visibility = [ + "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", + "//core:__subpackages__", + "//platform/public:__pkg__", + ], + deps = [ + ":logging", + ":types", + "//proto/connections:offline_wire_formats_portable_proto", + "//platform/api:comm", + "//platform/api:platform", + "//platform/base", + "//absl/container:flat_hash_map", + "//absl/strings", + "//webrtc/api:libjingle_peerconnection_api", + ], +) + +cc_library( + name = "logging", + hdrs = [ + "logging.h", + ], + visibility = [ + "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", + "//core:__subpackages__", + "//platform:__subpackages__", + ], + deps = [ + "//platform/base:logging", + ], +) + +cc_test( + name = "public_test", + size = "small", + srcs = [ + "atomic_boolean_test.cc", + "atomic_reference_test.cc", + "ble_test.cc", + "bluetooth_adapter_test.cc", + "bluetooth_classic_test.cc", + "cancelable_alarm_test.cc", + "condition_variable_test.cc", + "count_down_latch_test.cc", + "crypto_test.cc", + "future_test.cc", + "logging_test.cc", + "multi_thread_executor_test.cc", + "mutex_test.cc", + "pipe_test.cc", + "scheduled_executor_test.cc", + "single_thread_executor_test.cc", + "wifi_lan_test.cc", + ], + shard_count = 16, + deps = [ + ":comm", + ":logging", + ":types", + "//platform/base", + "//platform/base:test_util", + "//platform/impl/g3", # build_cleaner: keep + "//testing/base/public:gunit_main", + "//absl/strings", + "//absl/synchronization", + "//absl/time", + ], +) diff --git a/cpp/platform_v2/public/BUILD b/cpp/platform/public/BUILD.orig similarity index 89% rename from cpp/platform_v2/public/BUILD rename to cpp/platform/public/BUILD.orig index 6bd9ad66..31c87b6d 100644 --- a/cpp/platform_v2/public/BUILD +++ b/cpp/platform/public/BUILD.orig @@ -27,7 +27,6 @@ cc_library( visibility = [ "//core_v2:__subpackages__", "//platform_v2/base:__pkg__", - "//platform_v2/public:__pkg__", ], deps = [ ":logging", @@ -56,13 +55,11 @@ cc_library( "webrtc.h", "wifi_lan.h", ], - visibility = [ - "//core_v2:__subpackages__", - "//platform_v2/public:__pkg__", - ], + visibility = ["//core_v2:__subpackages__"], deps = [ ":logging", ":types", + "//proto/connections:offline_wire_formats_portable_proto", "//platform_v2/api:comm", "//platform_v2/api:platform", "//platform_v2/base", @@ -77,11 +74,7 @@ cc_library( hdrs = [ "logging.h", ], - visibility = [ - "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", - "//core_v2:__subpackages__", - "//platform_v2:__subpackages__", - ], + visibility = ["//core_v2:__subpackages__"], deps = [ "//platform_v2/base:logging", ], diff --git a/cpp/platform_v2/public/atomic_boolean.h b/cpp/platform/public/atomic_boolean.h similarity index 76% rename from cpp/platform_v2/public/atomic_boolean.h rename to cpp/platform/public/atomic_boolean.h index 08c5e833..992bbe0f 100644 --- a/cpp/platform_v2/public/atomic_boolean.h +++ b/cpp/platform/public/atomic_boolean.h @@ -1,17 +1,17 @@ -#ifndef PLATFORM_V2_PUBLIC_ATOMIC_BOOLEAN_H_ -#define PLATFORM_V2_PUBLIC_ATOMIC_BOOLEAN_H_ +#ifndef PLATFORM_PUBLIC_ATOMIC_BOOLEAN_H_ +#define PLATFORM_PUBLIC_ATOMIC_BOOLEAN_H_ #include -#include "platform_v2/api/atomic_boolean.h" -#include "platform_v2/api/platform.h" +#include "platform/api/atomic_boolean.h" +#include "platform/api/platform.h" namespace location { namespace nearby { // A boolean value that may be updated atomically. // See documentation in -// https://source.corp.google.com/piper///depot/google3/platform_v2/api/atomic_boolean.h +// https://source.corp.google.com/piper///depot/google3/platform/api/atomic_boolean.h class AtomicBoolean final : public api::AtomicBoolean { public: using Platform = api::ImplementationPlatform; @@ -31,4 +31,4 @@ class AtomicBoolean final : public api::AtomicBoolean { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_PUBLIC_ATOMIC_BOOLEAN_H_ +#endif // PLATFORM_PUBLIC_ATOMIC_BOOLEAN_H_ diff --git a/cpp/platform_v2/public/atomic_boolean_test.cc b/cpp/platform/public/atomic_boolean_test.cc similarity index 90% rename from cpp/platform_v2/public/atomic_boolean_test.cc rename to cpp/platform/public/atomic_boolean_test.cc index 00d92d0d..a25e7463 100644 --- a/cpp/platform_v2/public/atomic_boolean_test.cc +++ b/cpp/platform/public/atomic_boolean_test.cc @@ -1,4 +1,4 @@ -#include "platform_v2/public/atomic_boolean.h" +#include "platform/public/atomic_boolean.h" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/cpp/platform_v2/public/atomic_reference.h b/cpp/platform/public/atomic_reference.h similarity index 84% rename from cpp/platform_v2/public/atomic_reference.h rename to cpp/platform/public/atomic_reference.h index 66c40e9d..24c4cd7c 100644 --- a/cpp/platform_v2/public/atomic_reference.h +++ b/cpp/platform/public/atomic_reference.h @@ -1,13 +1,13 @@ -#ifndef PLATFORM_V2_PUBLIC_ATOMIC_REFERENCE_H_ -#define PLATFORM_V2_PUBLIC_ATOMIC_REFERENCE_H_ +#ifndef PLATFORM_PUBLIC_ATOMIC_REFERENCE_H_ +#define PLATFORM_PUBLIC_ATOMIC_REFERENCE_H_ #include #include -#include "platform_v2/api/atomic_reference.h" -#include "platform_v2/api/platform.h" -#include "platform_v2/public/mutex.h" -#include "platform_v2/public/mutex_lock.h" +#include "platform/api/atomic_reference.h" +#include "platform/api/platform.h" +#include "platform/public/mutex.h" +#include "platform/public/mutex_lock.h" namespace location { namespace nearby { @@ -70,4 +70,4 @@ class AtomicReference -#include "platform_v2/base/medium_environment.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/logging.h" +#include "platform/base/medium_environment.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/logging.h" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/cpp/platform_v2/public/bluetooth_adapter.h b/cpp/platform/public/bluetooth_adapter.h similarity index 93% rename from cpp/platform_v2/public/bluetooth_adapter.h rename to cpp/platform/public/bluetooth_adapter.h index d941b3b6..92c10e5e 100644 --- a/cpp/platform_v2/public/bluetooth_adapter.h +++ b/cpp/platform/public/bluetooth_adapter.h @@ -1,11 +1,11 @@ -#ifndef PLATFORM_V2_PUBLIC_BLUETOOTH_ADAPTER_H_ -#define PLATFORM_V2_PUBLIC_BLUETOOTH_ADAPTER_H_ +#ifndef PLATFORM_PUBLIC_BLUETOOTH_ADAPTER_H_ +#define PLATFORM_PUBLIC_BLUETOOTH_ADAPTER_H_ #include -#include "platform_v2/api/bluetooth_adapter.h" -#include "platform_v2/api/bluetooth_classic.h" -#include "platform_v2/api/platform.h" +#include "platform/api/bluetooth_adapter.h" +#include "platform/api/bluetooth_classic.h" +#include "platform/api/platform.h" #include "absl/strings/string_view.h" namespace location { @@ -111,4 +111,4 @@ class BluetoothAdapter final { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_PUBLIC_BLUETOOTH_ADAPTER_H_ +#endif // PLATFORM_PUBLIC_BLUETOOTH_ADAPTER_H_ diff --git a/cpp/platform_v2/public/bluetooth_adapter_test.cc b/cpp/platform/public/bluetooth_adapter_test.cc similarity index 92% rename from cpp/platform_v2/public/bluetooth_adapter_test.cc rename to cpp/platform/public/bluetooth_adapter_test.cc index 931ace51..737d4ee6 100644 --- a/cpp/platform_v2/public/bluetooth_adapter_test.cc +++ b/cpp/platform/public/bluetooth_adapter_test.cc @@ -1,7 +1,7 @@ -#include "platform_v2/public/bluetooth_adapter.h" +#include "platform/public/bluetooth_adapter.h" -#include "platform_v2/base/bluetooth_utils.h" -#include "platform_v2/public/logging.h" +#include "platform/base/bluetooth_utils.h" +#include "platform/public/logging.h" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/cpp/platform_v2/public/bluetooth_classic.cc b/cpp/platform/public/bluetooth_classic.cc similarity index 95% rename from cpp/platform_v2/public/bluetooth_classic.cc rename to cpp/platform/public/bluetooth_classic.cc index d3997d30..54f4e01e 100644 --- a/cpp/platform_v2/public/bluetooth_classic.cc +++ b/cpp/platform/public/bluetooth_classic.cc @@ -1,7 +1,7 @@ -#include "platform_v2/public/bluetooth_classic.h" +#include "platform/public/bluetooth_classic.h" -#include "platform_v2/public/logging.h" -#include "platform_v2/public/mutex_lock.h" +#include "platform/public/logging.h" +#include "platform/public/mutex_lock.h" namespace location { namespace nearby { diff --git a/cpp/platform_v2/public/bluetooth_classic.h b/cpp/platform/public/bluetooth_classic.h similarity index 93% rename from cpp/platform_v2/public/bluetooth_classic.h rename to cpp/platform/public/bluetooth_classic.h index 8d073f6b..5ba4060b 100644 --- a/cpp/platform_v2/public/bluetooth_classic.h +++ b/cpp/platform/public/bluetooth_classic.h @@ -1,18 +1,18 @@ -#ifndef PLATFORM_V2_PUBLIC_BLUETOOTH_CLASSIC_H_ -#define PLATFORM_V2_PUBLIC_BLUETOOTH_CLASSIC_H_ +#ifndef PLATFORM_PUBLIC_BLUETOOTH_CLASSIC_H_ +#define PLATFORM_PUBLIC_BLUETOOTH_CLASSIC_H_ #include #include -#include "platform_v2/api/bluetooth_classic.h" -#include "platform_v2/api/platform.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/exception.h" -#include "platform_v2/base/input_stream.h" -#include "platform_v2/base/listeners.h" -#include "platform_v2/base/output_stream.h" -#include "platform_v2/public/bluetooth_adapter.h" -#include "platform_v2/public/mutex.h" +#include "platform/api/bluetooth_classic.h" +#include "platform/api/platform.h" +#include "platform/base/byte_array.h" +#include "platform/base/exception.h" +#include "platform/base/input_stream.h" +#include "platform/base/listeners.h" +#include "platform/base/output_stream.h" +#include "platform/public/bluetooth_adapter.h" +#include "platform/public/mutex.h" #include "absl/container/flat_hash_map.h" namespace location { @@ -206,4 +206,4 @@ class BluetoothClassicMedium final { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_PUBLIC_BLUETOOTH_CLASSIC_H_ +#endif // PLATFORM_PUBLIC_BLUETOOTH_CLASSIC_H_ diff --git a/cpp/platform_v2/public/bluetooth_classic_test.cc b/cpp/platform/public/bluetooth_classic_test.cc similarity index 96% rename from cpp/platform_v2/public/bluetooth_classic_test.cc rename to cpp/platform/public/bluetooth_classic_test.cc index 42787a31..60253e9e 100644 --- a/cpp/platform_v2/public/bluetooth_classic_test.cc +++ b/cpp/platform/public/bluetooth_classic_test.cc @@ -1,12 +1,12 @@ -#include "platform_v2/public/bluetooth_classic.h" +#include "platform/public/bluetooth_classic.h" #include -#include "platform_v2/base/medium_environment.h" -#include "platform_v2/public/bluetooth_adapter.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/logging.h" -#include "platform_v2/public/single_thread_executor.h" +#include "platform/base/medium_environment.h" +#include "platform/public/bluetooth_adapter.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/logging.h" +#include "platform/public/single_thread_executor.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/time/time.h" diff --git a/cpp/platform_v2/public/cancelable.h b/cpp/platform/public/cancelable.h similarity index 77% rename from cpp/platform_v2/public/cancelable.h rename to cpp/platform/public/cancelable.h index 83f10291..a565e669 100644 --- a/cpp/platform_v2/public/cancelable.h +++ b/cpp/platform/public/cancelable.h @@ -1,10 +1,10 @@ -#ifndef PLATFORM_V2_PUBLIC_CANCELABLE_H_ -#define PLATFORM_V2_PUBLIC_CANCELABLE_H_ +#ifndef PLATFORM_PUBLIC_CANCELABLE_H_ +#define PLATFORM_PUBLIC_CANCELABLE_H_ #include #include -#include "platform_v2/api/cancelable.h" +#include "platform/api/cancelable.h" namespace location { namespace nearby { @@ -20,7 +20,7 @@ class Cancelable final { ~Cancelable() = default; // This constructor is used internally only, - // by other classes in "//platform_v2/public/". + // by other classes in "//platform/public/". explicit Cancelable(std::shared_ptr impl) : impl_(std::move(impl)) {} @@ -35,4 +35,4 @@ class Cancelable final { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_PUBLIC_CANCELABLE_H_ +#endif // PLATFORM_PUBLIC_CANCELABLE_H_ diff --git a/cpp/platform_v2/public/cancelable_alarm.h b/cpp/platform/public/cancelable_alarm.h similarity index 79% rename from cpp/platform_v2/public/cancelable_alarm.h rename to cpp/platform/public/cancelable_alarm.h index d00d6241..b2fd74c4 100644 --- a/cpp/platform_v2/public/cancelable_alarm.h +++ b/cpp/platform/public/cancelable_alarm.h @@ -1,15 +1,15 @@ -#ifndef PLATFORM_V2_PUBLIC_CANCELABLE_ALARM_H_ -#define PLATFORM_V2_PUBLIC_CANCELABLE_ALARM_H_ +#ifndef PLATFORM_PUBLIC_CANCELABLE_ALARM_H_ +#define PLATFORM_PUBLIC_CANCELABLE_ALARM_H_ #include #include #include #include -#include "platform_v2/public/cancelable.h" -#include "platform_v2/public/mutex.h" -#include "platform_v2/public/mutex_lock.h" -#include "platform_v2/public/scheduled_executor.h" +#include "platform/public/cancelable.h" +#include "platform/public/mutex.h" +#include "platform/public/mutex_lock.h" +#include "platform/public/scheduled_executor.h" namespace location { namespace nearby { @@ -58,4 +58,4 @@ class CancelableAlarm { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_PUBLIC_CANCELABLE_ALARM_H_ +#endif // PLATFORM_PUBLIC_CANCELABLE_ALARM_H_ diff --git a/cpp/platform_v2/public/cancelable_alarm_test.cc b/cpp/platform/public/cancelable_alarm_test.cc similarity index 90% rename from cpp/platform_v2/public/cancelable_alarm_test.cc rename to cpp/platform/public/cancelable_alarm_test.cc index 5bebf2cb..35a4ae8b 100644 --- a/cpp/platform_v2/public/cancelable_alarm_test.cc +++ b/cpp/platform/public/cancelable_alarm_test.cc @@ -1,7 +1,7 @@ -#include "platform_v2/public/cancelable_alarm.h" +#include "platform/public/cancelable_alarm.h" -#include "platform_v2/public/atomic_boolean.h" -#include "platform_v2/public/scheduled_executor.h" +#include "platform/public/atomic_boolean.h" +#include "platform/public/scheduled_executor.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/time/time.h" diff --git a/cpp/platform_v2/public/condition_variable.h b/cpp/platform/public/condition_variable.h similarity index 73% rename from cpp/platform_v2/public/condition_variable.h rename to cpp/platform/public/condition_variable.h index 81c9c951..4c39ed81 100644 --- a/cpp/platform_v2/public/condition_variable.h +++ b/cpp/platform/public/condition_variable.h @@ -1,10 +1,10 @@ -#ifndef PLATFORM_V2_PUBLIC_CONDITION_VARIABLE_H_ -#define PLATFORM_V2_PUBLIC_CONDITION_VARIABLE_H_ +#ifndef PLATFORM_PUBLIC_CONDITION_VARIABLE_H_ +#define PLATFORM_PUBLIC_CONDITION_VARIABLE_H_ -#include "platform_v2/api/condition_variable.h" -#include "platform_v2/api/platform.h" -#include "platform_v2/base/exception.h" -#include "platform_v2/public/mutex.h" +#include "platform/api/condition_variable.h" +#include "platform/api/platform.h" +#include "platform/base/exception.h" +#include "platform/public/mutex.h" namespace location { namespace nearby { @@ -32,4 +32,4 @@ class ConditionVariable final { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_PUBLIC_CONDITION_VARIABLE_H_ +#endif // PLATFORM_PUBLIC_CONDITION_VARIABLE_H_ diff --git a/cpp/platform_v2/public/condition_variable_test.cc b/cpp/platform/public/condition_variable_test.cc similarity index 87% rename from cpp/platform_v2/public/condition_variable_test.cc rename to cpp/platform/public/condition_variable_test.cc index 6e0f7c2b..e71c54a9 100644 --- a/cpp/platform_v2/public/condition_variable_test.cc +++ b/cpp/platform/public/condition_variable_test.cc @@ -1,9 +1,9 @@ -#include "platform_v2/public/condition_variable.h" +#include "platform/public/condition_variable.h" -#include "platform_v2/public/logging.h" -#include "platform_v2/public/mutex.h" -#include "platform_v2/public/single_thread_executor.h" -#include "platform_v2/public/system_clock.h" +#include "platform/public/logging.h" +#include "platform/public/mutex.h" +#include "platform/public/single_thread_executor.h" +#include "platform/public/system_clock.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/time/time.h" diff --git a/cpp/platform_v2/public/count_down_latch.h b/cpp/platform/public/count_down_latch.h similarity index 77% rename from cpp/platform_v2/public/count_down_latch.h rename to cpp/platform/public/count_down_latch.h index 37a76901..921691e9 100644 --- a/cpp/platform_v2/public/count_down_latch.h +++ b/cpp/platform/public/count_down_latch.h @@ -1,11 +1,11 @@ -#ifndef PLATFORM_V2_PUBLIC_COUNT_DOWN_LATCH_H_ -#define PLATFORM_V2_PUBLIC_COUNT_DOWN_LATCH_H_ +#ifndef PLATFORM_PUBLIC_COUNT_DOWN_LATCH_H_ +#define PLATFORM_PUBLIC_COUNT_DOWN_LATCH_H_ #include -#include "platform_v2/api/count_down_latch.h" -#include "platform_v2/api/platform.h" -#include "platform_v2/base/exception.h" +#include "platform/api/count_down_latch.h" +#include "platform/api/platform.h" +#include "platform/base/exception.h" #include "absl/time/time.h" namespace location { @@ -37,4 +37,4 @@ class CountDownLatch final { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_PUBLIC_COUNT_DOWN_LATCH_H_ +#endif // PLATFORM_PUBLIC_COUNT_DOWN_LATCH_H_ diff --git a/cpp/platform_v2/public/count_down_latch_test.cc b/cpp/platform/public/count_down_latch_test.cc similarity index 90% rename from cpp/platform_v2/public/count_down_latch_test.cc rename to cpp/platform/public/count_down_latch_test.cc index 52aed3fd..46d844c2 100644 --- a/cpp/platform_v2/public/count_down_latch_test.cc +++ b/cpp/platform/public/count_down_latch_test.cc @@ -1,6 +1,6 @@ -#include "platform_v2/public/count_down_latch.h" +#include "platform/public/count_down_latch.h" -#include "platform_v2/public/single_thread_executor.h" +#include "platform/public/single_thread_executor.h" #include "gtest/gtest.h" namespace location { diff --git a/cpp/platform/public/crypto.h b/cpp/platform/public/crypto.h new file mode 100644 index 00000000..c948d957 --- /dev/null +++ b/cpp/platform/public/crypto.h @@ -0,0 +1,6 @@ +#ifndef PLATFORM_PUBLIC_CRYPTO_H_ +#define PLATFORM_PUBLIC_CRYPTO_H_ + +#include "platform/api/crypto.h" + +#endif // PLATFORM_PUBLIC_CRYPTO_H_ diff --git a/cpp/platform_v2/public/crypto_test.cc b/cpp/platform/public/crypto_test.cc similarity index 91% rename from cpp/platform_v2/public/crypto_test.cc rename to cpp/platform/public/crypto_test.cc index 3499831b..b5ded2d6 100644 --- a/cpp/platform_v2/public/crypto_test.cc +++ b/cpp/platform/public/crypto_test.cc @@ -1,6 +1,6 @@ -#include "platform_v2/public/crypto.h" +#include "platform/public/crypto.h" -#include "platform_v2/base/byte_array.h" +#include "platform/base/byte_array.h" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/cpp/platform_v2/public/file.h b/cpp/platform/public/file.h similarity index 88% rename from cpp/platform_v2/public/file.h rename to cpp/platform/public/file.h index 1bd6ae30..edaf9c77 100644 --- a/cpp/platform_v2/public/file.h +++ b/cpp/platform/public/file.h @@ -1,17 +1,17 @@ -#ifndef PLATFORM_V2_PUBLIC_FILE_H_ -#define PLATFORM_V2_PUBLIC_FILE_H_ +#ifndef PLATFORM_PUBLIC_FILE_H_ +#define PLATFORM_PUBLIC_FILE_H_ #include #include #include -#include "platform_v2/api/input_file.h" -#include "platform_v2/api/output_file.h" -#include "platform_v2/api/platform.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/exception.h" -#include "platform_v2/base/input_stream.h" -#include "platform_v2/base/output_stream.h" +#include "platform/api/input_file.h" +#include "platform/api/output_file.h" +#include "platform/api/platform.h" +#include "platform/base/byte_array.h" +#include "platform/base/exception.h" +#include "platform/base/input_stream.h" +#include "platform/base/output_stream.h" namespace location { namespace nearby { @@ -98,4 +98,4 @@ class OutputFile final { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_PUBLIC_FILE_H_ +#endif // PLATFORM_PUBLIC_FILE_H_ diff --git a/cpp/platform_v2/public/future.h b/cpp/platform/public/future.h similarity index 88% rename from cpp/platform_v2/public/future.h rename to cpp/platform/public/future.h index 80babc9c..400aeb3f 100644 --- a/cpp/platform_v2/public/future.h +++ b/cpp/platform/public/future.h @@ -1,7 +1,7 @@ -#ifndef PLATFORM_V2_PUBLIC_FUTURE_H_ -#define PLATFORM_V2_PUBLIC_FUTURE_H_ +#ifndef PLATFORM_PUBLIC_FUTURE_H_ +#define PLATFORM_PUBLIC_FUTURE_H_ -#include "platform_v2/public/settable_future.h" +#include "platform/public/settable_future.h" namespace location { namespace nearby { @@ -41,4 +41,4 @@ class Future final { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_PUBLIC_FUTURE_H_ +#endif // PLATFORM_PUBLIC_FUTURE_H_ diff --git a/cpp/platform_v2/public/future_test.cc b/cpp/platform/public/future_test.cc similarity index 96% rename from cpp/platform_v2/public/future_test.cc rename to cpp/platform/public/future_test.cc index 60515e36..9a19f271 100644 --- a/cpp/platform_v2/public/future_test.cc +++ b/cpp/platform/public/future_test.cc @@ -1,6 +1,6 @@ -#include "platform_v2/public/future.h" +#include "platform/public/future.h" -#include "platform_v2/public/single_thread_executor.h" +#include "platform/public/single_thread_executor.h" #include "gtest/gtest.h" #include "absl/time/clock.h" #include "absl/time/time.h" diff --git a/cpp/platform/public/logging.h b/cpp/platform/public/logging.h new file mode 100644 index 00000000..08063aaf --- /dev/null +++ b/cpp/platform/public/logging.h @@ -0,0 +1,6 @@ +#ifndef PLATFORM_PUBLIC_LOGGING_H_ +#define PLATFORM_PUBLIC_LOGGING_H_ + +#include "platform/base/logging.h" + +#endif // PLATFORM_PUBLIC_LOGGING_H_ diff --git a/cpp/platform_v2/public/logging_test.cc b/cpp/platform/public/logging_test.cc similarity index 95% rename from cpp/platform_v2/public/logging_test.cc rename to cpp/platform/public/logging_test.cc index 16aa64d1..23359eba 100644 --- a/cpp/platform_v2/public/logging_test.cc +++ b/cpp/platform/public/logging_test.cc @@ -1,4 +1,4 @@ -#include "platform_v2/public/logging.h" +#include "platform/public/logging.h" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/cpp/platform_v2/public/multi_thread_executor.h b/cpp/platform/public/multi_thread_executor.h similarity index 74% rename from cpp/platform_v2/public/multi_thread_executor.h rename to cpp/platform/public/multi_thread_executor.h index f43ffc98..af44792a 100644 --- a/cpp/platform_v2/public/multi_thread_executor.h +++ b/cpp/platform/public/multi_thread_executor.h @@ -1,8 +1,8 @@ -#ifndef PLATFORM_V2_PUBLIC_MULTI_THREAD_EXECUTOR_H_ -#define PLATFORM_V2_PUBLIC_MULTI_THREAD_EXECUTOR_H_ +#ifndef PLATFORM_PUBLIC_MULTI_THREAD_EXECUTOR_H_ +#define PLATFORM_PUBLIC_MULTI_THREAD_EXECUTOR_H_ -#include "platform_v2/api/platform.h" -#include "platform_v2/public/submittable_executor.h" +#include "platform/api/platform.h" +#include "platform/public/submittable_executor.h" namespace location { namespace nearby { @@ -25,4 +25,4 @@ class MultiThreadExecutor final : public SubmittableExecutor { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_PUBLIC_MULTI_THREAD_EXECUTOR_H_ +#endif // PLATFORM_PUBLIC_MULTI_THREAD_EXECUTOR_H_ diff --git a/cpp/platform_v2/public/multi_thread_executor_test.cc b/cpp/platform/public/multi_thread_executor_test.cc similarity index 95% rename from cpp/platform_v2/public/multi_thread_executor_test.cc rename to cpp/platform/public/multi_thread_executor_test.cc index 914aa363..6c775032 100644 --- a/cpp/platform_v2/public/multi_thread_executor_test.cc +++ b/cpp/platform/public/multi_thread_executor_test.cc @@ -1,9 +1,9 @@ -#include "platform_v2/public/multi_thread_executor.h" +#include "platform/public/multi_thread_executor.h" #include #include -#include "platform_v2/base/exception.h" +#include "platform/base/exception.h" #include "gtest/gtest.h" #include "absl/synchronization/mutex.h" #include "absl/time/clock.h" diff --git a/cpp/platform_v2/public/mutex.h b/cpp/platform/public/mutex.h similarity index 90% rename from cpp/platform_v2/public/mutex.h rename to cpp/platform/public/mutex.h index 99333a27..29e0da67 100644 --- a/cpp/platform_v2/public/mutex.h +++ b/cpp/platform/public/mutex.h @@ -1,10 +1,10 @@ -#ifndef PLATFORM_V2_PUBLIC_MUTEX_H_ -#define PLATFORM_V2_PUBLIC_MUTEX_H_ +#ifndef PLATFORM_PUBLIC_MUTEX_H_ +#define PLATFORM_PUBLIC_MUTEX_H_ #include -#include "platform_v2/api/mutex.h" -#include "platform_v2/api/platform.h" +#include "platform/api/mutex.h" +#include "platform/api/platform.h" #include "absl/base/thread_annotations.h" namespace location { @@ -61,4 +61,4 @@ class ABSL_LOCKABLE RecursiveMutex final { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_PUBLIC_MUTEX_H_ +#endif // PLATFORM_PUBLIC_MUTEX_H_ diff --git a/cpp/platform_v2/public/mutex_lock.h b/cpp/platform/public/mutex_lock.h similarity index 75% rename from cpp/platform_v2/public/mutex_lock.h rename to cpp/platform/public/mutex_lock.h index 2275ee56..c6a40d0a 100644 --- a/cpp/platform_v2/public/mutex_lock.h +++ b/cpp/platform/public/mutex_lock.h @@ -1,8 +1,8 @@ -#ifndef PLATFORM_V2_PUBLIC_MUTEX_LOCK_H_ -#define PLATFORM_V2_PUBLIC_MUTEX_LOCK_H_ +#ifndef PLATFORM_PUBLIC_MUTEX_LOCK_H_ +#define PLATFORM_PUBLIC_MUTEX_LOCK_H_ -#include "platform_v2/api/mutex.h" -#include "platform_v2/public/mutex.h" +#include "platform/api/mutex.h" +#include "platform/public/mutex.h" #include "absl/base/thread_annotations.h" namespace location { @@ -28,4 +28,4 @@ class ABSL_SCOPED_LOCKABLE MutexLock final { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_PUBLIC_MUTEX_LOCK_H_ +#endif // PLATFORM_PUBLIC_MUTEX_LOCK_H_ diff --git a/cpp/platform_v2/public/mutex_test.cc b/cpp/platform/public/mutex_test.cc similarity index 94% rename from cpp/platform_v2/public/mutex_test.cc rename to cpp/platform/public/mutex_test.cc index 54760cfd..c61d8de6 100644 --- a/cpp/platform_v2/public/mutex_test.cc +++ b/cpp/platform/public/mutex_test.cc @@ -1,7 +1,7 @@ -#include "platform_v2/public/mutex.h" +#include "platform/public/mutex.h" -#include "platform_v2/public/condition_variable.h" -#include "platform_v2/public/single_thread_executor.h" +#include "platform/public/condition_variable.h" +#include "platform/public/single_thread_executor.h" #include "gtest/gtest.h" #include "absl/synchronization/mutex.h" #include "absl/time/clock.h" diff --git a/cpp/platform_v2/public/pipe.cc b/cpp/platform/public/pipe.cc similarity index 68% rename from cpp/platform_v2/public/pipe.cc rename to cpp/platform/public/pipe.cc index f9ae3b11..c64d36a8 100644 --- a/cpp/platform_v2/public/pipe.cc +++ b/cpp/platform/public/pipe.cc @@ -1,8 +1,8 @@ -#include "platform_v2/public/pipe.h" +#include "platform/public/pipe.h" -#include "platform_v2/api/condition_variable.h" -#include "platform_v2/api/mutex.h" -#include "platform_v2/api/platform.h" +#include "platform/api/condition_variable.h" +#include "platform/api/mutex.h" +#include "platform/api/platform.h" namespace location { namespace nearby { diff --git a/cpp/platform_v2/public/pipe.h b/cpp/platform/public/pipe.h similarity index 57% rename from cpp/platform_v2/public/pipe.h rename to cpp/platform/public/pipe.h index f277e156..555cd979 100644 --- a/cpp/platform_v2/public/pipe.h +++ b/cpp/platform/public/pipe.h @@ -1,13 +1,13 @@ -#ifndef PLATFORM_V2_PUBLIC_PIPE_H_ -#define PLATFORM_V2_PUBLIC_PIPE_H_ +#ifndef PLATFORM_PUBLIC_PIPE_H_ +#define PLATFORM_PUBLIC_PIPE_H_ -#include "platform_v2/base/base_pipe.h" +#include "platform/base/base_pipe.h" namespace location { namespace nearby { // See for details: -// http://google3/platform_v2/base/base_pipe.h +// http://google3/platform/base/base_pipe.h class Pipe final : public BasePipe { public: Pipe(); @@ -19,4 +19,4 @@ class Pipe final : public BasePipe { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_PUBLIC_PIPE_H_ +#endif // PLATFORM_PUBLIC_PIPE_H_ diff --git a/cpp/platform_v2/public/pipe_test.cc b/cpp/platform/public/pipe_test.cc similarity index 98% rename from cpp/platform_v2/public/pipe_test.cc rename to cpp/platform/public/pipe_test.cc index c8a7af89..84880cd7 100644 --- a/cpp/platform_v2/public/pipe_test.cc +++ b/cpp/platform/public/pipe_test.cc @@ -1,4 +1,4 @@ -#include "platform_v2/public/pipe.h" +#include "platform/public/pipe.h" #include @@ -6,8 +6,8 @@ #include #include -#include "platform_v2/base/prng.h" -#include "platform_v2/base/runnable.h" +#include "platform/base/prng.h" +#include "platform/base/runnable.h" #include "gtest/gtest.h" namespace location { diff --git a/cpp/platform_v2/public/scheduled_executor.h b/cpp/platform/public/scheduled_executor.h similarity index 81% rename from cpp/platform_v2/public/scheduled_executor.h rename to cpp/platform/public/scheduled_executor.h index ca90e32d..6dea9e55 100644 --- a/cpp/platform_v2/public/scheduled_executor.h +++ b/cpp/platform/public/scheduled_executor.h @@ -1,16 +1,16 @@ -#ifndef PLATFORM_V2_PUBLIC_SCHEDULED_EXECUTOR_H_ -#define PLATFORM_V2_PUBLIC_SCHEDULED_EXECUTOR_H_ +#ifndef PLATFORM_PUBLIC_SCHEDULED_EXECUTOR_H_ +#define PLATFORM_PUBLIC_SCHEDULED_EXECUTOR_H_ #include #include #include -#include "platform_v2/api/platform.h" -#include "platform_v2/api/scheduled_executor.h" -#include "platform_v2/base/runnable.h" -#include "platform_v2/public/cancelable.h" -#include "platform_v2/public/mutex.h" -#include "platform_v2/public/mutex_lock.h" +#include "platform/api/platform.h" +#include "platform/api/scheduled_executor.h" +#include "platform/base/runnable.h" +#include "platform/public/cancelable.h" +#include "platform/public/mutex.h" +#include "platform/public/mutex_lock.h" #include "absl/time/time.h" namespace location { @@ -78,4 +78,4 @@ class ScheduledExecutor final { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_PUBLIC_SCHEDULED_EXECUTOR_H_ +#endif // PLATFORM_PUBLIC_SCHEDULED_EXECUTOR_H_ diff --git a/cpp/platform_v2/public/scheduled_executor_test.cc b/cpp/platform/public/scheduled_executor_test.cc similarity index 96% rename from cpp/platform_v2/public/scheduled_executor_test.cc rename to cpp/platform/public/scheduled_executor_test.cc index 5a760b69..95720137 100644 --- a/cpp/platform_v2/public/scheduled_executor_test.cc +++ b/cpp/platform/public/scheduled_executor_test.cc @@ -1,9 +1,9 @@ -#include "platform_v2/public/scheduled_executor.h" +#include "platform/public/scheduled_executor.h" #include #include -#include "platform_v2/base/exception.h" +#include "platform/base/exception.h" #include "gtest/gtest.h" #include "absl/synchronization/mutex.h" #include "absl/time/clock.h" diff --git a/cpp/platform_v2/public/settable_future.h b/cpp/platform/public/settable_future.h similarity index 89% rename from cpp/platform_v2/public/settable_future.h rename to cpp/platform/public/settable_future.h index 4a45aab0..b175cbfa 100644 --- a/cpp/platform_v2/public/settable_future.h +++ b/cpp/platform/public/settable_future.h @@ -1,12 +1,12 @@ -#ifndef PLATFORM_V2_PUBLIC_SETTABLE_FUTURE_H_ -#define PLATFORM_V2_PUBLIC_SETTABLE_FUTURE_H_ +#ifndef PLATFORM_PUBLIC_SETTABLE_FUTURE_H_ +#define PLATFORM_PUBLIC_SETTABLE_FUTURE_H_ #include -#include "platform_v2/public/condition_variable.h" -#include "platform_v2/public/mutex.h" -#include "platform_v2/public/mutex_lock.h" -#include "platform_v2/public/system_clock.h" +#include "platform/public/condition_variable.h" +#include "platform/public/mutex.h" +#include "platform/public/mutex_lock.h" +#include "platform/public/system_clock.h" namespace location { namespace nearby { @@ -111,4 +111,4 @@ class SettableFuture : public api::SettableFuture { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_PUBLIC_SETTABLE_FUTURE_H_ +#endif // PLATFORM_PUBLIC_SETTABLE_FUTURE_H_ diff --git a/cpp/platform_v2/public/single_thread_executor.h b/cpp/platform/public/single_thread_executor.h similarity index 77% rename from cpp/platform_v2/public/single_thread_executor.h rename to cpp/platform/public/single_thread_executor.h index 369af90c..16c57ce0 100644 --- a/cpp/platform_v2/public/single_thread_executor.h +++ b/cpp/platform/public/single_thread_executor.h @@ -1,7 +1,7 @@ -#ifndef PLATFORM_V2_PUBLIC_SINGLE_THREAD_EXECUTOR_H_ -#define PLATFORM_V2_PUBLIC_SINGLE_THREAD_EXECUTOR_H_ +#ifndef PLATFORM_PUBLIC_SINGLE_THREAD_EXECUTOR_H_ +#define PLATFORM_PUBLIC_SINGLE_THREAD_EXECUTOR_H_ -#include "platform_v2/public/submittable_executor.h" +#include "platform/public/submittable_executor.h" namespace location { namespace nearby { @@ -24,4 +24,4 @@ class SingleThreadExecutor final : public SubmittableExecutor { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_PUBLIC_SINGLE_THREAD_EXECUTOR_H_ +#endif // PLATFORM_PUBLIC_SINGLE_THREAD_EXECUTOR_H_ diff --git a/cpp/platform_v2/public/single_thread_executor_test.cc b/cpp/platform/public/single_thread_executor_test.cc similarity index 94% rename from cpp/platform_v2/public/single_thread_executor_test.cc rename to cpp/platform/public/single_thread_executor_test.cc index eedbe576..1608b5a8 100644 --- a/cpp/platform_v2/public/single_thread_executor_test.cc +++ b/cpp/platform/public/single_thread_executor_test.cc @@ -1,9 +1,9 @@ -#include "platform_v2/public/single_thread_executor.h" +#include "platform/public/single_thread_executor.h" #include #include -#include "platform_v2/base/exception.h" +#include "platform/base/exception.h" #include "gtest/gtest.h" #include "absl/synchronization/mutex.h" #include "absl/time/clock.h" diff --git a/cpp/platform_v2/public/submittable_executor.h b/cpp/platform/public/submittable_executor.h similarity index 85% rename from cpp/platform_v2/public/submittable_executor.h rename to cpp/platform/public/submittable_executor.h index d398dd69..7154f944 100644 --- a/cpp/platform_v2/public/submittable_executor.h +++ b/cpp/platform/public/submittable_executor.h @@ -1,18 +1,18 @@ -#ifndef PLATFORM_V2_PUBLIC_SUBMITTABLE_EXECUTOR_H_ -#define PLATFORM_V2_PUBLIC_SUBMITTABLE_EXECUTOR_H_ +#ifndef PLATFORM_PUBLIC_SUBMITTABLE_EXECUTOR_H_ +#define PLATFORM_PUBLIC_SUBMITTABLE_EXECUTOR_H_ #include #include #include #include -#include "platform_v2/api/executor.h" -#include "platform_v2/api/submittable_executor.h" -#include "platform_v2/base/callable.h" -#include "platform_v2/base/runnable.h" -#include "platform_v2/public/future.h" -#include "platform_v2/public/mutex.h" -#include "platform_v2/public/mutex_lock.h" +#include "platform/api/executor.h" +#include "platform/api/submittable_executor.h" +#include "platform/base/callable.h" +#include "platform/base/runnable.h" +#include "platform/public/future.h" +#include "platform/public/mutex.h" +#include "platform/public/mutex_lock.h" namespace location { namespace nearby { @@ -100,4 +100,4 @@ class SubmittableExecutor : public api::SubmittableExecutor { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_PUBLIC_SUBMITTABLE_EXECUTOR_H_ +#endif // PLATFORM_PUBLIC_SUBMITTABLE_EXECUTOR_H_ diff --git a/cpp/platform/public/system_clock.h b/cpp/platform/public/system_clock.h new file mode 100644 index 00000000..37ecb5f9 --- /dev/null +++ b/cpp/platform/public/system_clock.h @@ -0,0 +1,6 @@ +#ifndef PLATFORM_PUBLIC_SYSTEM_CLOCK_H_ +#define PLATFORM_PUBLIC_SYSTEM_CLOCK_H_ + +#include "platform/api/system_clock.h" + +#endif // PLATFORM_PUBLIC_SYSTEM_CLOCK_H_ diff --git a/cpp/platform_v2/public/webrtc.h b/cpp/platform/public/webrtc.h similarity index 86% rename from cpp/platform_v2/public/webrtc.h rename to cpp/platform/public/webrtc.h index 8884e66d..ad7d4f18 100644 --- a/cpp/platform_v2/public/webrtc.h +++ b/cpp/platform/public/webrtc.h @@ -1,10 +1,10 @@ -#ifndef PLATFORM_V2_PUBLIC_WEBRTC_H_ -#define PLATFORM_V2_PUBLIC_WEBRTC_H_ +#ifndef PLATFORM_PUBLIC_WEBRTC_H_ +#define PLATFORM_PUBLIC_WEBRTC_H_ #include -#include "platform_v2/api/platform.h" -#include "platform_v2/api/webrtc.h" +#include "platform/api/platform.h" +#include "platform/api/webrtc.h" #include "webrtc/api/peer_connection_interface.h" namespace location { @@ -56,9 +56,10 @@ class WebRtcMedium final { // Returns a signaling messenger for sending WebRTC signaling messages. std::unique_ptr GetSignalingMessenger( - absl::string_view self_id) { + absl::string_view self_id, + const connections::LocationHint& location_hint) { return std::make_unique( - impl_->GetSignalingMessenger(self_id)); + impl_->GetSignalingMessenger(self_id, location_hint)); } bool IsValid() const { return impl_ != nullptr; } @@ -70,4 +71,4 @@ class WebRtcMedium final { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_PUBLIC_WEBRTC_H_ +#endif // PLATFORM_PUBLIC_WEBRTC_H_ diff --git a/cpp/platform_v2/public/wifi_lan.cc b/cpp/platform/public/wifi_lan.cc similarity index 85% rename from cpp/platform_v2/public/wifi_lan.cc rename to cpp/platform/public/wifi_lan.cc index 9a1e0240..7e3152e2 100644 --- a/cpp/platform_v2/public/wifi_lan.cc +++ b/cpp/platform/public/wifi_lan.cc @@ -1,14 +1,16 @@ -#include "platform_v2/public/wifi_lan.h" +#include "platform/public/wifi_lan.h" -#include "platform_v2/public/logging.h" -#include "platform_v2/public/mutex_lock.h" +#include "platform/public/logging.h" +#include "platform/public/mutex_lock.h" namespace location { namespace nearby { bool WifiLanMedium::StartAdvertising(const std::string& service_id, - const std::string& service_info_name) { - return impl_->StartAdvertising(service_id, service_info_name); + const std::string& service_info_name, + const std::string& endpoint_info_name) { + return impl_->StartAdvertising(service_id, service_info_name, + endpoint_info_name); } bool WifiLanMedium::StopAdvertising(const std::string& service_id) { @@ -37,13 +39,14 @@ bool WifiLanMedium::StartDiscovery(const std::string& service_id, "Discovering (again) service=%p, impl=%p, " "service_info_name=%s", &context.service, &service, - service.GetName().c_str()); + service.GetServiceName().c_str()); } else { context.service = WifiLanService(&service); - NEARBY_LOG( - INFO, - "Discovering service=%p, impl=%p, service_info_name=%s", - &context.service, &service, service.GetName().c_str()); + NEARBY_LOG(INFO, + "Discovering service=%p, impl=%p, " + "service_info_name=%s", + &context.service, &service, + service.GetServiceName().c_str()); } discovered_service_callback_.service_discovered_cb( context.service, service_id); @@ -119,7 +122,7 @@ WifiLanSocket WifiLanMedium::Connect(WifiLanService& service, NEARBY_LOG( INFO, "WifiLanMedium::Connect: service=%p [impl=%p, service_info_name=%s]", - &service, &service.GetImpl(), service.GetName().c_str()); + &service, &service.GetImpl(), service.GetServiceName().c_str()); return WifiLanSocket(impl_->Connect(service.GetImpl(), service_id)); } diff --git a/cpp/platform_v2/public/wifi_lan.h b/cpp/platform/public/wifi_lan.h similarity index 89% rename from cpp/platform_v2/public/wifi_lan.h rename to cpp/platform/public/wifi_lan.h index fa6ba565..1806aa2e 100644 --- a/cpp/platform_v2/public/wifi_lan.h +++ b/cpp/platform/public/wifi_lan.h @@ -1,19 +1,19 @@ -#ifndef PLATFORM_V2_PUBLIC_WIFI_LAN_H_ -#define PLATFORM_V2_PUBLIC_WIFI_LAN_H_ +#ifndef PLATFORM_PUBLIC_WIFI_LAN_H_ +#define PLATFORM_PUBLIC_WIFI_LAN_H_ -#include "platform_v2/api/platform.h" -#include "platform_v2/api/wifi_lan.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/input_stream.h" -#include "platform_v2/base/output_stream.h" -#include "platform_v2/public/mutex.h" +#include "platform/api/platform.h" +#include "platform/api/wifi_lan.h" +#include "platform/base/byte_array.h" +#include "platform/base/input_stream.h" +#include "platform/base/output_stream.h" +#include "platform/public/mutex.h" #include "absl/container/flat_hash_map.h" namespace location { namespace nearby { // Opaque wrapper over a WifiLan service which contains packed -// |WifiLanServiceInfo| string name. +// |WifiLanServiceInfo| string name and the TXT Record. class WifiLanService final { public: WifiLanService() = default; @@ -22,7 +22,11 @@ class WifiLanService final { explicit WifiLanService(api::WifiLanService* service) : impl_(service) {} ~WifiLanService() = default; - std::string GetName() const { return impl_->GetName(); } + std::string GetServiceName() const { return impl_->GetServiceName(); } + + std::string GetTxtRecord(const std::string& key) const { + return impl_->GetTxtRecord(key); + } api::WifiLanService& GetImpl() { return *impl_; } bool IsValid() const { return impl_ != nullptr; } @@ -114,7 +118,8 @@ class WifiLanMedium final { ~WifiLanMedium() = default; bool StartAdvertising(const std::string& service_id, - const std::string& service_info_name); + const std::string& service_info_name, + const std::string& endpoint_info_name); bool StopAdvertising(const std::string& service_id); // Returns true once the WifiLan discovery has been initiated. @@ -160,4 +165,4 @@ class WifiLanMedium final { } // namespace nearby } // namespace location -#endif // PLATFORM_V2_PUBLIC_WIFI_LAN_H_ +#endif // PLATFORM_PUBLIC_WIFI_LAN_H_ diff --git a/cpp/platform_v2/public/wifi_lan_test.cc b/cpp/platform/public/wifi_lan_test.cc similarity index 88% rename from cpp/platform_v2/public/wifi_lan_test.cc rename to cpp/platform/public/wifi_lan_test.cc index 2e89e09f..11796882 100644 --- a/cpp/platform_v2/public/wifi_lan_test.cc +++ b/cpp/platform/public/wifi_lan_test.cc @@ -1,10 +1,10 @@ -#include "platform_v2/public/wifi_lan.h" +#include "platform/public/wifi_lan.h" #include -#include "platform_v2/base/medium_environment.h" -#include "platform_v2/public/count_down_latch.h" -#include "platform_v2/public/logging.h" +#include "platform/base/medium_environment.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/logging.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/strings/string_view.h" @@ -15,6 +15,7 @@ namespace { constexpr absl::string_view kServiceID{"com.google.location.nearby.apps.test"}; constexpr absl::string_view kServiceInfoName{"Simulated service info name"}; +constexpr absl::string_view kEndpointName{"Simulated endpoint name"}; class WifiLanMediumTest : public ::testing::Test { protected: @@ -46,9 +47,10 @@ TEST_F(WifiLanMediumTest, CanStartAdvertising) { WifiLanMedium wifi_b; std::string service_id(kServiceID); std::string service_info_name{kServiceInfoName}; + std::string endpoint_info_name{kEndpointName}; CountDownLatch found_latch(1); - wifi_a.StartAdvertising(service_id, service_info_name); + wifi_a.StartAdvertising(service_id, service_info_name, endpoint_info_name); EXPECT_TRUE(wifi_b.StartDiscovery( service_id, DiscoveredServiceCallback{ @@ -70,6 +72,7 @@ TEST_F(WifiLanMediumTest, CanStartDiscovery) { WifiLanMedium wifi_b; std::string service_id(kServiceID); std::string service_info_name{kServiceInfoName}; + std::string endpoint_info_name{kEndpointName}; CountDownLatch found_latch(1); CountDownLatch lost_latch(1); @@ -86,7 +89,8 @@ TEST_F(WifiLanMediumTest, CanStartDiscovery) { lost_latch.CountDown(); }, }); - EXPECT_TRUE(wifi_b.StartAdvertising(service_id, service_info_name)); + EXPECT_TRUE(wifi_b.StartAdvertising(service_id, service_info_name, + endpoint_info_name)); EXPECT_TRUE(found_latch.Await(absl::Milliseconds(1000)).result()); EXPECT_TRUE(wifi_b.StopAdvertising(service_id)); EXPECT_TRUE(lost_latch.Await(absl::Milliseconds(1000)).result()); @@ -100,6 +104,7 @@ TEST_F(WifiLanMediumTest, CanStopDiscovery) { WifiLanMedium wifi_b; std::string service_id(kServiceID); std::string service_info_name{kServiceInfoName}; + std::string endpoint_info_name{kEndpointName}; CountDownLatch found_latch(1); CountDownLatch lost_latch(1); @@ -116,7 +121,8 @@ TEST_F(WifiLanMediumTest, CanStopDiscovery) { lost_latch.CountDown(); }, }); - EXPECT_TRUE(wifi_b.StartAdvertising(service_id, service_info_name)); + EXPECT_TRUE(wifi_b.StartAdvertising(service_id, service_info_name, + endpoint_info_name)); EXPECT_TRUE(found_latch.Await(absl::Milliseconds(1000)).result()); EXPECT_TRUE(wifi_a.StopDiscovery(service_id)); EXPECT_TRUE(wifi_b.StopAdvertising(service_id)); @@ -130,6 +136,7 @@ TEST_F(WifiLanMediumTest, CanStartAcceptingConnectionsAndConnect) { WifiLanMedium wifi_b; std::string service_id(kServiceID); std::string service_info_name{kServiceInfoName}; + std::string endpoint_info_name{kEndpointName}; CountDownLatch found_latch(1); CountDownLatch accepted_latch(1); @@ -141,12 +148,12 @@ TEST_F(WifiLanMediumTest, CanStartAcceptingConnectionsAndConnect) { [&found_latch, &discovered_service]( WifiLanService& service, const std::string& service_id) { NEARBY_LOG(INFO, "Service discovered: %s, %p", - service.GetName().c_str(), &service); + service.GetServiceName().c_str(), &service); discovered_service = &service; found_latch.CountDown(); }, }); - wifi_b.StartAdvertising(service_id, service_info_name); + wifi_b.StartAdvertising(service_id, service_info_name, endpoint_info_name); wifi_b.StartAcceptingConnections( service_id, AcceptedConnectionCallback{ diff --git a/cpp/platform/reliability_utils.cc b/cpp/platform/reliability_utils.cc deleted file mode 100644 index 1f296eb8..00000000 --- a/cpp/platform/reliability_utils.cc +++ /dev/null @@ -1,42 +0,0 @@ -#include "platform/reliability_utils.h" - -namespace location { -namespace nearby { - -bool ReliabilityUtils::attemptRepeatedly(Ptr runnable, - const std::string &runnable_name, - Ptr recovery_runnable) { - return false; -} - -bool ReliabilityUtils::attemptRepeatedly(Ptr runnable, - const std::string &runnable_name, - Ptr recovery_runnable, - const AtomicBoolean &isCancelled) { - return false; -} - -bool ReliabilityUtils::attemptRepeatedly(Ptr runnable, - const std::string &runnable_name, - std::int64_t recovery_pause_millis) { - return false; -} - -bool ReliabilityUtils::attemptRepeatedly(Ptr runnable, - const std::string &runnable_name, - std::int64_t recovery_pause_millis, - const AtomicBoolean &isCancelled) { - return false; -} - -bool ReliabilityUtils::attemptRepeatedly(Ptr runnable, - const std::string &runnable_name, - int num_attempts, - std::int64_t recovery_pause_millis, - Ptr recovery_runnable, - const AtomicBoolean &isCancelled) { - return false; -} - -} // namespace nearby -} // namespace location diff --git a/cpp/platform/reliability_utils.h b/cpp/platform/reliability_utils.h deleted file mode 100644 index a4262e89..00000000 --- a/cpp/platform/reliability_utils.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef PLATFORM_RELIABILITY_UTILS_H_ -#define PLATFORM_RELIABILITY_UTILS_H_ - -#include - -#include "platform/api/atomic_boolean.h" -#include "platform/port/string.h" -#include "platform/ptr.h" -#include "platform/runnable.h" - -namespace location { -namespace nearby { - -class ReliabilityUtils { - public: - static bool attemptRepeatedly(Ptr runnable, - const std::string& runnable_name, - Ptr recovery_runnable); - static bool attemptRepeatedly(Ptr runnable, - const std::string& runnable_name, - Ptr recovery_runnable, - const AtomicBoolean& isCancelled); - static bool attemptRepeatedly(Ptr runnable, - const std::string& runnable_name, - std::int64_t recovery_pause_millis); - static bool attemptRepeatedly(Ptr runnable, - const std::string& runnable_name, - std::int64_t recovery_pause_millis, - const AtomicBoolean& isCancelled); - - private: - static bool attemptRepeatedly(Ptr runnable, - const std::string& runnable_name, - int num_attempts, - std::int64_t recovery_pause_millis, - Ptr recovery_runnable, - const AtomicBoolean& isCancelled); -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_RELIABILITY_UTILS_H_ diff --git a/cpp/platform/runnable.h b/cpp/platform/runnable.h deleted file mode 100644 index e70bd512..00000000 --- a/cpp/platform/runnable.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef PLATFORM_RUNNABLE_H_ -#define PLATFORM_RUNNABLE_H_ - -namespace location { -namespace nearby { - -// The Runnable interface should be implemented by any class whose instances are -// intended to be executed by a thread. The class must define a method named -// run() with no arguments. -// -// https://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html -class Runnable { - public: - virtual ~Runnable() {} - - virtual void run() = 0; -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_RUNNABLE_H_ diff --git a/cpp/platform/settable_future_test.cc b/cpp/platform/settable_future_test.cc deleted file mode 100644 index 2de63970..00000000 --- a/cpp/platform/settable_future_test.cc +++ /dev/null @@ -1,84 +0,0 @@ -#include "platform/api/settable_future.h" - -#include "platform/api/platform.h" -#include "platform/ptr.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -namespace location { -namespace nearby { - -namespace { - -enum TestEnum { - kValue1 = 1, - kValue2 = 2, -}; - -enum class ScopedTestEnum { - kValue1 = 1, - kValue2 = 2, -}; - -struct BigSizedStruct { - int data[100]{}; -}; - -bool operator==(const BigSizedStruct& a, const BigSizedStruct& b) { - return memcmp(a.data, b.data, sizeof(BigSizedStruct::data)) == 0; -} - -bool operator!=(const BigSizedStruct& a, const BigSizedStruct& b) { - return !(a == b); -} - -} // namespace - -TEST(SettableFutureTest, SupportIntegralTypes) { - auto p = platform::ImplementationPlatform::createSettableFuture(); - p->set(5); - ASSERT_EQ(p->get().exception(), Exception::kSuccess); - ASSERT_EQ(p->get().result(), 5); -} - -TEST(SettableFutureTest, SetExceptionIsPropagated) { - auto p = platform::ImplementationPlatform::createSettableFuture(); - p->setException({Exception::kIo}); - ASSERT_EQ(p->get().exception(), Exception::kIo); -} - -TEST(SettableFutureTest, SupportEnum) { - auto p = platform::ImplementationPlatform::createSettableFuture(); - p->set(TestEnum::kValue1); - ASSERT_EQ(p->get().exception(), Exception::kSuccess); - ASSERT_EQ(p->get().result(), TestEnum::kValue1); -} - -TEST(SettableFutureTest, SupportScopedEnum) { - auto p = - platform::ImplementationPlatform::createSettableFuture(); - p->set(ScopedTestEnum::kValue1); - ASSERT_EQ(p->get().exception(), Exception::kSuccess); - ASSERT_EQ(p->get().result(), ScopedTestEnum::kValue1); -} - -TEST(SettableFutureTest, SetTakesCopyOfValue) { - // Default constructor is zero-initalizing all data in BigSizedStruct. - BigSizedStruct v1; - auto p = platform::ImplementationPlatform::createSettableFuture< - BigSizedStruct>(); - v1.data[0] = 5; // Changing value before calling set() will affect stored - v1.data[7] = 3; // value. - p->set(v1); - v1.data[1] = 6; // Changing value after calling set() will not affect stored - v1.data[5] = 4; // value. - ASSERT_EQ(p->get().exception(), Exception::kSuccess); - BigSizedStruct v2 = p->get().result(); - ASSERT_NE(v1, v2); - v1.data[1] = 0; - v1.data[5] = 0; - ASSERT_EQ(v2, v1); -} - -} // namespace nearby -} // namespace location diff --git a/cpp/platform/synchronized.h b/cpp/platform/synchronized.h deleted file mode 100644 index 81b37789..00000000 --- a/cpp/platform/synchronized.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef PLATFORM_SYNCHRONIZED_H_ -#define PLATFORM_SYNCHRONIZED_H_ - -#include "platform/api/lock.h" -#include "platform/ptr.h" - -namespace location { -namespace nearby { - -// An RAII mechanism to acquire a Lock over a block of code. -// -// https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html -// https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html -class Synchronized { - public: - explicit Synchronized(Ptr lock) : lock_(lock) { lock_->lock(); } - ~Synchronized() { lock_->unlock(); } - - private: - Ptr lock_; -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_SYNCHRONIZED_H_ diff --git a/cpp/platform_v2/api/BUILD b/cpp/platform_v2/api/BUILD deleted file mode 100644 index ca6d809f..00000000 --- a/cpp/platform_v2/api/BUILD +++ /dev/null @@ -1,76 +0,0 @@ -cc_library( - name = "types", - hdrs = [ - "atomic_boolean.h", - "atomic_reference.h", - "cancelable.h", - "condition_variable.h", - "count_down_latch.h", - "crypto.h", - "executor.h", - "future.h", - "input_file.h", - "listenable_future.h", - "log_message.h", - "mutex.h", - "output_file.h", - "scheduled_executor.h", - "settable_future.h", - "submittable_executor.h", - "system_clock.h", - ], - visibility = [ - "//platform_v2/base:__pkg__", - "//platform_v2/impl:__subpackages__", - "//platform_v2/public:__pkg__", - ], - deps = [ - "//platform_v2/base", - "//absl/base:core_headers", - "//absl/strings", - "//absl/time", - ], -) - -cc_library( - name = "comm", - hdrs = [ - "ble.h", - "ble_v2.h", - "bluetooth_adapter.h", - "bluetooth_classic.h", - "server_sync.h", - "webrtc.h", - "wifi.h", - "wifi_lan.h", - ], - visibility = [ - "//platform_v2/base:__pkg__", - "//platform_v2/impl:__subpackages__", - "//platform_v2/public:__pkg__", - ], - deps = [ - "//platform_v2/base", - "//absl/strings", - "//absl/types:optional", - "//webrtc/api:libjingle_peerconnection_api", - ], -) - -cc_library( - name = "platform", - hdrs = [ - "platform.h", - ], - visibility = [ - "//platform_v2/base:__pkg__", - "//platform_v2/impl:__subpackages__", - "//platform_v2/public:__pkg__", - ], - deps = [ - ":comm", - ":types", - "//platform_v2/base", - "//absl/strings", - ], -) diff --git a/cpp/platform_v2/api/atomic_boolean.h b/cpp/platform_v2/api/atomic_boolean.h deleted file mode 100644 index fff1bfa8..00000000 --- a/cpp/platform_v2/api/atomic_boolean.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef PLATFORM_V2_API_ATOMIC_BOOLEAN_H_ -#define PLATFORM_V2_API_ATOMIC_BOOLEAN_H_ - -namespace location { -namespace nearby { -namespace api { - -// A boolean value that may be updated atomically. -class AtomicBoolean { - public: - virtual ~AtomicBoolean() = default; - - // Atomically read and return current value. - virtual bool Get() const = 0; - - // Atomically exchange original value with a new one. Return previous value. - virtual bool Set(bool value) = 0; -}; - -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_ATOMIC_BOOLEAN_H_ diff --git a/cpp/platform_v2/api/atomic_reference.h b/cpp/platform_v2/api/atomic_reference.h deleted file mode 100644 index 2c0a2d50..00000000 --- a/cpp/platform_v2/api/atomic_reference.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef PLATFORM_V2_API_ATOMIC_REFERENCE_H_ -#define PLATFORM_V2_API_ATOMIC_REFERENCE_H_ - -#include - -namespace location { -namespace nearby { -namespace api { - -// Type that allows 32-bit atomic reads and writes. -class AtomicUint32 { - public: - virtual ~AtomicUint32() = default; - - // Atomically reads and returns stored value. - virtual std::uint32_t Get() const = 0; - - // Atomically stores value. - virtual void Set(std::uint32_t value) = 0; -}; - -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_ATOMIC_REFERENCE_H_ diff --git a/cpp/platform_v2/api/ble.h b/cpp/platform_v2/api/ble.h deleted file mode 100644 index 608574cf..00000000 --- a/cpp/platform_v2/api/ble.h +++ /dev/null @@ -1,109 +0,0 @@ -#ifndef PLATFORM_V2_API_BLE_H_ -#define PLATFORM_V2_API_BLE_H_ - -#include "platform_v2/api/bluetooth_classic.h" -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/input_stream.h" -#include "platform_v2/base/output_stream.h" - -namespace location { -namespace nearby { -namespace api { - -// Opaque wrapper over a BLE peripheral. Must contain enough data about a -// particular BLE device to connect to its GATT server. -class BlePeripheral { - public: - virtual ~BlePeripheral() = default; - - virtual std::string GetName() const = 0; - - virtual ByteArray GetAdvertisementBytes( - const std::string& service_id) const = 0; -}; - -class BleSocket { - public: - virtual ~BleSocket() = default; - - // Returns the InputStream of the BleSocket. - // On error, returned stream will report Exception::kIo on any operation. - // - // The returned object is not owned by the caller, and can be invalidated once - // the BleSocket object is destroyed. - virtual InputStream& GetInputStream() = 0; - - // Returns the OutputStream of the BleSocket. - // On error, returned stream will report Exception::kIo on any operation. - // - // The returned object is not owned by the caller, and can be invalidated once - // the BleSocket object is destroyed. - virtual OutputStream& GetOutputStream() = 0; - - // Conforms to the same contract as - // https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#close(). - // - // Returns Exception::kIo on error, Exception::kSuccess otherwise. - virtual Exception Close() = 0; - - // Returns valid BlePeripheral pointer if there is a connection, and - // nullptr otherwise. - virtual BlePeripheral* GetRemotePeripheral() = 0; -}; - -// Container of operations that can be performed over the BLE medium. -class BleMedium { - public: - virtual ~BleMedium() = default; - - virtual bool StartAdvertising( - const std::string& service_id, const ByteArray& advertisement_bytes, - const std::string& fast_advertisement_service_uuid) = 0; - virtual bool StopAdvertising(const std::string& service_id) = 0; - - // Callback that is invoked when a discovered peripheral is found or lost. - struct DiscoveredPeripheralCallback { - std::function - peripheral_discovered_cb = - DefaultCallback(); - std::function - peripheral_lost_cb = - DefaultCallback(); - }; - - // Returns true once the BLE scan has been initiated. - virtual bool StartScanning(const std::string& service_id, - const std::string& fast_advertisement_service_uuid, - DiscoveredPeripheralCallback callback) = 0; - - // Returns true once BLE scanning for service_id is well and truly stopped; - // after this returns, there must be no more invocations of the - // DiscoveredPeripheralCallback passed in to StartScanning() for service_id. - virtual bool StopScanning(const std::string& service_id) = 0; - - // Callback that is invoked when a new connection is accepted. - struct AcceptedConnectionCallback { - std::function - accepted_cb = DefaultCallback(); - }; - - // Returns true once BLE socket connection requests to service_id can be - // accepted. - virtual bool StartAcceptingConnections( - const std::string& service_id, AcceptedConnectionCallback callback) = 0; - virtual bool StopAcceptingConnections(const std::string& service_id) = 0; - - // Connects to a BLE peripheral. - // On success, returns a new BleSocket. - // On error, returns nullptr. - virtual std::unique_ptr Connect(BlePeripheral& peripheral, - const std::string& service_id) = 0; -}; - -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_BLE_H_ diff --git a/cpp/platform_v2/api/ble_v2.h b/cpp/platform_v2/api/ble_v2.h deleted file mode 100644 index ae094d1e..00000000 --- a/cpp/platform_v2/api/ble_v2.h +++ /dev/null @@ -1,392 +0,0 @@ -#ifndef PLATFORM_V2_API_BLE_V2_H_ -#define PLATFORM_V2_API_BLE_V2_H_ - -#include -#include -#include -#include -#include -#include - -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/exception.h" -#include "absl/strings/string_view.h" -#include "absl/types/optional.h" - -namespace location { -namespace nearby { -namespace api { -namespace ble_v2 { - -// https://developer.android.com/reference/android/bluetooth/le/AdvertiseData -// -// Bundle of data found in a BLE advertisement. -// -// All service UUIDs will conform to the 16-bit Bluetooth base UUID, -// 0000xxxx-0000-1000-8000-00805F9B34FB. This makes it possible to store two -// byte service UUIDs in the advertisement. -struct BleAdvertisementData { - using TxPowerLevel = int8_t; - - static const TxPowerLevel kUnspecifiedTxPowerLevel = - std::numeric_limits::min(); - - bool is_connectable; - // When set to kUnspecifiedTxPowerLevel, TX power should not be included in - // the advertisement data. - TxPowerLevel tx_power_level; - // When set to an empty string, local name should not be included in the - // advertisement data. - std::string local_name; - // When set to an empty vector, the set of 16-bit service class UUIDs should - // not be included in the advertisement data. - std::set service_uuids; - // Maps service UUIDs to their service data. - std::map service_data; -}; - -// Opaque wrapper over a BLE peripheral. Must be able to uniquely identify a -// peripheral so that we can connect to its GATT server. -class BlePeripheral { - public: - virtual ~BlePeripheral() {} - - // https://developer.android.com/reference/android/bluetooth/BluetoothDevice#getAddress() - // - // This should be the MAC address when possible. If the implementation is - // unable to retrieve that, any unique identifier should suffice. - virtual std::string GetId() const = 0; -}; - -// https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic -// -// Representation of a GATT characteristic. -class GattCharacteristic { - public: - virtual ~GattCharacteristic() {} - - // Possible permissions of a GATT characteristic. - enum class Permission { - kUnknown = 0, - kRead = 1, - kWrite = 2, - kLast, - }; - - // Possible properties of a GATT characteristic. - enum class Property { - kUnknown = 0, - kRead = 1, - kWrite = 2, - kIndicate = 3, - kLast, - }; - - // Returns the UUID of this characteristic. - virtual std::string GetUuid() = 0; - - // Returns the UUID of the containing GATT service. - virtual std::string GetServiceUuid() = 0; -}; - -// https://developer.android.com/reference/android/bluetooth/BluetoothGatt -// -// Representation of a client GATT connection to a remote GATT server. -class ClientGattConnection { - public: - virtual ~ClientGattConnection() {} - - // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#getDevice() - // - // Retrieves the BLE peripheral that this connection is tied to. - virtual BlePeripheral& GetPeripheral() = 0; - - // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#discoverServices() - // - // Discovers all available services and characteristics on this connection. - // Returns whether or not discovery finished successfully. - // - // This function should block until discovery has finished. - virtual bool DiscoverServices() = 0; - - // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#getService(java.util.UUID) - // https://developer.android.com/reference/android/bluetooth/BluetoothGattService.html#getCharacteristic(java.util.UUID) - // - // Retrieves a GATT characteristic. On error, does not return a value. - // - // DiscoverServices() should be called before this method to fetch all - // available services and characteristics first. - // - // It is okay for duplicate services to exist, as long as the specified - // characteristic UUID is unique among all services of the same UUID. - virtual absl::optional GetCharacteristic( - absl::string_view service_uuid, - absl::string_view characteristic_uuid) = 0; - - // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#readCharacteristic(android.bluetooth.BluetoothGattCharacteristic) - // https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#getValue() - // - // Reads a GATT characteristic. No value is returned upon error. - virtual absl::optional ReadCharacteristic( - const GattCharacteristic& characteristic) = 0; - - // https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#setValue(byte[]) - // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic) - // - // Sends a remote characteristic write request to the server and returns - // whether or not it was successful. - virtual bool WriteCharacteristic(const GattCharacteristic& characteristic, - const ByteArray& value) = 0; - - // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#disconnect() - // - // Disconnects a GATT connection. - virtual void Disconnect() = 0; -}; - -// https://developer.android.com/reference/android/bluetooth/BluetoothGattServer -// -// Representation of a server GATT connection to a remote GATT client. -class ServerGattConnection { - public: - virtual ~ServerGattConnection() {} - - // https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#setValue(byte[]) - // https://developer.android.com/reference/android/bluetooth/BluetoothGattServer.html#notifyCharacteristicChanged(android.bluetooth.BluetoothDevice,%20android.bluetooth.BluetoothGattCharacteristic,%20boolean) - // - // Sends a notification (via indication) to the client that a characteristic - // has changed with the given value. Returns whether or not it was successful. - // - // The value sent does not have to reflect the locally stored characteristic - // value. To update the local value, call GattServer::UpdateCharacteristic. - virtual bool SendCharacteristic(const GattCharacteristic& characteristic, - const ByteArray& value) = 0; -}; - -// Callback for asynchronous events on the client side of a GATT connection. -class ClientGattConnectionLifeCycleCallback { - public: - virtual ~ClientGattConnectionLifeCycleCallback() {} - - // Called when the client is disconnected from the GATT server. - virtual void OnDisconnected(ClientGattConnection* connection) = 0; -}; - -// Callback for asynchronous events on the server side of a GATT connection. -class ServerGattConnectionLifeCycleCallback { - public: - virtual ~ServerGattConnectionLifeCycleCallback() {} - - // Called when a remote peripheral connected to us and subscribed to one of - // our characteristics. - virtual void OnCharacteristicSubscription( - ServerGattConnection* connection, - const GattCharacteristic& characteristic) = 0; - - // Called when a remote peripheral unsubscribed from one of our - // characteristics. - virtual void OnCharacteristicUnsubscription( - ServerGattConnection* connection, - const GattCharacteristic& characteristic) = 0; -}; - -// https://developer.android.com/reference/android/bluetooth/BluetoothGattServer -// -// Representation of a BLE GATT server. -class GattServer { - public: - virtual ~GattServer() {} - - // Creates a characteristic and adds it to the GATT server under the given - // characteristic and service UUIDs. Returns no value upon error. - // - // Characteristics of the same service UUID should be put under one - // service rather than many services with the same UUID. - // - // If the INDICATE property is included, the characteristic should include the - // official Bluetooth Client Characteristic Configuration descriptor with UUID - // 0x2902 and a WRITE permission. This allows remote clients to write to this - // descriptor and subscribe for characteristic changes. For more information - // about this descriptor, please go to: - // https://www.bluetooth.com/specifications/Gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.Gatt.client_characteristic_configuration.xml - virtual absl::optional CreateCharacteristic( - absl::string_view service_uuid, absl::string_view characteristic_uuid, - const std::set& permissions, - const std::set& properties) = 0; - - // https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#setValue(byte[]) - // - // Locally updates the value of a characteristic and returns whether or not it - // was successful. - // Takes ownership of (and is responsible for destroying) the passed-in - // 'value'. - virtual bool UpdateCharacteristic(const GattCharacteristic& characteristic, - const ByteArray& value) = 0; - - // Stops a GATT server. - virtual void Stop() = 0; -}; - -// A BLE socket representation. -class BleSocket { - public: - virtual ~BleSocket() {} - - // Returns the remote BLE peripheral tied to this socket. - virtual BlePeripheral& GetRemotePeripheral() = 0; - - // Writes a message on the socket and blocks until finished. Returns - // Exception::kIo upon error, and Exception::kSuccess otherwise. - virtual Exception Write(const ByteArray& message) = 0; - - // Closes the socket and blocks until finished. Returns Exception::kIo upon - // error, and Exception::kSuccess otherwise. - virtual Exception Close() = 0; -}; - -// Callback for asynchronous events on a BleSocket object. -class BleSocketLifeCycleCallback { - public: - virtual ~BleSocketLifeCycleCallback() {} - - // Called when a message arrives on a socket. - virtual void OnMessageReceived(BleSocket* socket, - const ByteArray& message) = 0; - - // Called when a socket gets disconnected. - virtual void OnDisconnected(BleSocket* socket) = 0; -}; - -// Callback for asynchronous events on the server side of a BleSocket object. -class ServerBleSocketLifeCycleCallback : public BleSocketLifeCycleCallback { - public: - ~ServerBleSocketLifeCycleCallback() override {} - - // Called when a new incoming socket has been established. - virtual void OnSocketEstablished(BleSocket* socket) = 0; -}; - -// The main BLE medium used inside of Nearby. This serves as the entry point for -// all BLE and GATT related operations. -class BleMedium { - public: - using Mtu = uint32_t; - - virtual ~BleMedium() {} - - // Coarse representation of power settings throughout all BLE operations. - enum class PowerMode { - kUnknown = 0, - kLow = 1, - kHigh = 2, - kLast, - }; - - // https://developer.android.com/reference/android/bluetooth/le/BluetoothLeAdvertiser.html#startAdvertising(android.bluetooth.le.AdvertiseSettings,%20android.bluetooth.le.AdvertiseData,%20android.bluetooth.le.AdvertiseData,%20android.bluetooth.le.AdvertiseCallback) - // - // Starts BLE advertising and returns whether or not it was successful. - // - // Power mode should be interpreted in the following way: - // LOW: - // - Advertising interval = ~1000ms - // - TX power = low - // HIGH: - // - Advertising interval = ~100ms - // - TX power = high - virtual bool StartAdvertising(const BleAdvertisementData& advertisement_data, - const BleAdvertisementData& scan_response, - PowerMode power_mode) = 0; - - // https://developer.android.com/reference/android/bluetooth/le/BluetoothLeAdvertiser.html#stopAdvertising(android.bluetooth.le.AdvertiseCallback) - // - // Stops advertising. - virtual void StopAdvertising() = 0; - - // https://developer.android.com/reference/android/bluetooth/le/ScanCallback - // - // Callback for BLE scan results. - class ScanCallback { - public: - virtual ~ScanCallback() {} - - // https://developer.android.com/reference/android/bluetooth/le/ScanCallback.html#onScanResult(int,%20android.bluetooth.le.ScanResult) - // - // Called when a BLE advertisement is discovered. - // - // The passed in advertisement_data is the merged combination of both - // advertisement data and scan response. - // - // Every discovery of an advertisement should be reported, even if the - // advertisement was discovered before. - // - // Ownership of the BleAdvertisementData transfers to the caller at this - // point. - virtual void OnAdvertisementFound( - BlePeripheral* peripheral, - const BleAdvertisementData& advertisement_data) = 0; - }; - - // https://developer.android.com/reference/android/bluetooth/le/BluetoothLeScanner.html#startScan(java.util.List%3Candroid.bluetooth.le.ScanFilter%3E,%20android.bluetooth.le.ScanSettings,%20android.bluetooth.le.ScanCallback) - // - // Starts scanning and returns whether or not it was successful. - // - // Power mode should be interpreted in the following way: - // LOW: - // - Scan window = ~512ms - // - Scan interval = ~5120ms - // HIGH: - // - Scan window = ~4096ms - // - Scan interval = ~4096ms - virtual bool StartScanning(const std::set& service_uuids, - PowerMode power_mode, - const ScanCallback& scan_callback) = 0; - - // https://developer.android.com/reference/android/bluetooth/le/BluetoothLeScanner.html#stopScan(android.bluetooth.le.ScanCallback) - // - // Stops scanning. - virtual void StopScanning() = 0; - - // https://developer.android.com/reference/android/bluetooth/BluetoothManager#openGattServer(android.content.Context,%20android.bluetooth.BluetoothGattServerCallback) - // - // Starts a GATT server. Returns a nullptr upon error. - virtual std::unique_ptr StartGattServer( - const ServerGattConnectionLifeCycleCallback& callback) = 0; - - // Starts listening for incoming BLE sockets and returns false upon error. - virtual bool StartListeningForIncomingBleSockets( - const ServerBleSocketLifeCycleCallback& callback) = 0; - - // Stops listening for incoming BLE sockets. - virtual void StopListeningForIncomingBleSockets() = 0; - - // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#connectGatt(android.content.Context,%20boolean,%20android.bluetooth.BluetoothGattCallback) - // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#requestConnectionPriority(int) - // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#requestMtu(int) - // - // Connects to a GATT server and negotiates the specified connection - // parameters. Returns nullptr upon error. - // - // Both connection interval and MTU can be negotiated on a best-effort basis. - // - // Power mode should be interpreted in the following way: - // LOW: - // - Connection interval = ~11.25ms - 15ms - // HIGH: - // - Connection interval = ~100ms - 125ms - virtual std::unique_ptr ConnectToGattServer( - BlePeripheral* peripheral, Mtu mtu, PowerMode power_mode, - const ClientGattConnectionLifeCycleCallback& callback) = 0; - - // Establishes a BLE socket to the specified remote peripheral. Returns - // nullptr on error. - virtual std::unique_ptr EstablishBleSocket( - BlePeripheral* peripheral, - const BleSocketLifeCycleCallback& callback) = 0; -}; - -} // namespace ble_v2 -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_BLE_V2_H_ diff --git a/cpp/platform_v2/api/bluetooth_adapter.h b/cpp/platform_v2/api/bluetooth_adapter.h deleted file mode 100644 index 96ec2e7a..00000000 --- a/cpp/platform_v2/api/bluetooth_adapter.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef PLATFORM_V2_API_BLUETOOTH_ADAPTER_H_ -#define PLATFORM_V2_API_BLUETOOTH_ADAPTER_H_ - -#include - -#include "absl/strings/string_view.h" - -namespace location { -namespace nearby { -namespace api { - -// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html -class BluetoothAdapter { - public: - virtual ~BluetoothAdapter() = default; - - // Eligible statuses of the BluetoothAdapter. - enum class Status { - kDisabled, - kEnabled, - }; - - // Synchronously sets the status of the BluetoothAdapter to 'status', and - // returns true if the operation was a success. - virtual bool SetStatus(Status status) = 0; - // Returns true if the BluetoothAdapter's current status is - // Status::Value::kEnabled. - virtual bool IsEnabled() const = 0; - - // Scan modes of a BluetoothAdapter, as described at - // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getScanMode(). - enum class ScanMode { - kUnknown, - kNone, - kConnectable, - kConnectableDiscoverable, - }; - - // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getScanMode() - // - // Returns ScanMode::kUnknown on error. - virtual ScanMode GetScanMode() const = 0; - // Synchronously sets the scan mode of the adapter, and returns true if the - // operation was a success. - virtual bool SetScanMode(ScanMode scan_mode) = 0; - - // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getName() - // Returns an empty string on error - virtual std::string GetName() const = 0; - // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#setName(java.lang.String) - virtual bool SetName(absl::string_view name) = 0; - - // Returns BT MAC address assigned to this adapter. - virtual std::string GetMacAddress() const = 0; -}; - -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_BLUETOOTH_ADAPTER_H_ diff --git a/cpp/platform_v2/api/bluetooth_classic.h b/cpp/platform_v2/api/bluetooth_classic.h deleted file mode 100644 index 5b334830..00000000 --- a/cpp/platform_v2/api/bluetooth_classic.h +++ /dev/null @@ -1,146 +0,0 @@ -#ifndef PLATFORM_V2_API_BLUETOOTH_CLASSIC_H_ -#define PLATFORM_V2_API_BLUETOOTH_CLASSIC_H_ - -#include -#include - -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/exception.h" -#include "platform_v2/base/input_stream.h" -#include "platform_v2/base/listeners.h" -#include "platform_v2/base/output_stream.h" - -namespace location { -namespace nearby { -namespace api { - -// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html. -class BluetoothDevice { - public: - virtual ~BluetoothDevice() = default; - - // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName() - virtual std::string GetName() const = 0; - - // Returns BT MAC address assigned to this device. - virtual std::string GetMacAddress() const = 0; -}; - -// https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html. -class BluetoothSocket { - public: - virtual ~BluetoothSocket() = default; - - // NOTE: - // It is an undefined behavior if GetInputStream() or GetOutputStream() is - // called for a not-connected BluetoothSocket, i.e. any object that is not - // returned by BluetoothClassicMedium::ConnectToService() for client side or - // BluetoothServerSocket::Accept() for server side of connection. - - // Returns the InputStream of this connected BluetoothSocket. - virtual InputStream& GetInputStream() = 0; - - // Returns the OutputStream of this connected BluetoothSocket. - virtual OutputStream& GetOutputStream() = 0; - - // Closes both input and output streams, marks Socket as closed. - // After this call object should be treated as not connected. - // Returns Exception::kIo on error, Exception::kSuccess otherwise. - virtual Exception Close() = 0; - - // https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#getRemoteDevice() - // Returns valid BluetoothDevice pointer if there is a connection, and - // nullptr otherwise. - virtual BluetoothDevice* GetRemoteDevice() = 0; -}; - -// https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html. -class BluetoothServerSocket { - public: - virtual ~BluetoothServerSocket() = default; - - // https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#accept() - // - // Blocks until either: - // - at least one incoming connection request is available, or - // - ServerSocket is closed. - // On success, returns connected socket, ready to exchange data. - // Returns nullptr on error. - // Once error is reported, it is permanent, and ServerSocket has to be closed. - virtual std::unique_ptr Accept() = 0; - - // https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#close() - // - // Returns Exception::kIo on error, Exception::kSuccess otherwise. - virtual Exception Close() = 0; -}; - -// Container of operations that can be performed over the Bluetooth Classic -// medium. -class BluetoothClassicMedium { - public: - virtual ~BluetoothClassicMedium() = default; - - struct DiscoveryCallback { - // BluetoothDevice is a proxy object created as a result of BT discovery. - // Its lifetime spans between calls to device_discovered_cb and - // device_lost_cb. - // It is safe to use BluetoothDevice in device_discovered_cb() callback - // and at any time afterwards, until device_lost_cb() is called. - // It is not safe to use BluetoothDevice after returning from - // device_lost_cb() callback. - std::function device_discovered_cb = - DefaultCallback(); - std::function device_name_changed_cb = - DefaultCallback(); - std::function device_lost_cb = - DefaultCallback(); - }; - - // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery() - // - // Returns true once the process of discovery has been initiated. - virtual bool StartDiscovery(DiscoveryCallback discovery_callback) = 0; - // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#cancelDiscovery() - // - // Returns true once discovery is well and truly stopped; after this returns, - // there must be no more invocations of the DiscoveryCallback passed in to - // StartDiscovery(). - virtual bool StopDiscovery() = 0; - - // A combination of - // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createInsecureRfcommSocketToServiceRecord - // followed by - // https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#connect(). - // - // service_uuid is the canonical textual representation - // (https://en.wikipedia.org/wiki/Universally_unique_identifier#Format) of a - // type 3 name-based - // (https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions_3_and_5_(namespace_name-based)) - // UUID. - // - // On success, returns a new BluetoothSocket. - // On error, returns nullptr. - virtual std::unique_ptr ConnectToService( - BluetoothDevice& remote_device, const std::string& service_uuid) = 0; - - // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#listenUsingInsecureRfcommWithServiceRecord - // - // service_uuid is the canonical textual representation - // (https://en.wikipedia.org/wiki/Universally_unique_identifier#Format) of a - // type 3 name-based - // (https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions_3_and_5_(namespace_name-based)) - // UUID. - // - // Returns nullptr error. - virtual std::unique_ptr ListenForService( - const std::string& service_name, const std::string& service_uuid) = 0; - - virtual BluetoothDevice* GetRemoteDevice(const std::string& mac_address) = 0; -}; - -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_BLUETOOTH_CLASSIC_H_ diff --git a/cpp/platform_v2/api/condition_variable.h b/cpp/platform_v2/api/condition_variable.h deleted file mode 100644 index a11b74dc..00000000 --- a/cpp/platform_v2/api/condition_variable.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef PLATFORM_V2_API_CONDITION_VARIABLE_H_ -#define PLATFORM_V2_API_CONDITION_VARIABLE_H_ - -#include "platform_v2/base/exception.h" -#include "absl/time/clock.h" - -namespace location { -namespace nearby { -namespace api { - -// The ConditionVariable class is a synchronization primitive that can be used -// to block a thread, or multiple threads at the same time, until another thread -// both modifies a shared variable (the condition), and notifies the -// ConditionVariable. -class ConditionVariable { - public: - virtual ~ConditionVariable() {} - - // Notifies all the waiters that condition state has changed. - virtual void Notify() = 0; - - // Waits indefinitely for Notify to be called. - // May return prematurely in case of interrupt, if supported by platform. - // Returns kSuccess, or kInterrupted on interrupt. - virtual Exception Wait() = 0; - - // Waits while timeout has not expired for Notify to be called. - // May return prematurely in case of interrupt, if supported by platform. - // Returns kSuccess, or kInterrupted on interrupt. - virtual Exception Wait(absl::Duration timeout) = 0; -}; - -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_CONDITION_VARIABLE_H_ diff --git a/cpp/platform_v2/api/count_down_latch.h b/cpp/platform_v2/api/count_down_latch.h deleted file mode 100644 index 7e0d407f..00000000 --- a/cpp/platform_v2/api/count_down_latch.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef PLATFORM_V2_API_COUNT_DOWN_LATCH_H_ -#define PLATFORM_V2_API_COUNT_DOWN_LATCH_H_ - -#include - -#include "platform_v2/base/exception.h" -#include "absl/time/time.h" - -namespace location { -namespace nearby { -namespace api { - -// A synchronization aid that allows one or more threads to wait until a set of -// operations being performed in other threads completes. -// -// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CountDownLatch.html -class CountDownLatch { - public: - virtual ~CountDownLatch() = default; - - virtual Exception Await() = 0; // throws Exception::kInterrupted - virtual ExceptionOr Await( - absl::Duration timeout) = 0; // throws Exception::kInterrupted - virtual void CountDown() = 0; -}; - -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_COUNT_DOWN_LATCH_H_ diff --git a/cpp/platform_v2/api/executor.h b/cpp/platform_v2/api/executor.h deleted file mode 100644 index a4a26990..00000000 --- a/cpp/platform_v2/api/executor.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef PLATFORM_V2_API_EXECUTOR_H_ -#define PLATFORM_V2_API_EXECUTOR_H_ - -#include "platform_v2/base/runnable.h" - -namespace location { -namespace nearby { -namespace api { - -int GetCurrentTid(); - -// This abstract class is the superclass of all classes representing an -// Executor. -class Executor { - public: - // Before returning from destructor, executor must wait for all pending - // jobs to finish. - virtual ~Executor() = default; - // https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html#execute-java.lang.Runnable- - virtual void Execute(Runnable&& runnable) = 0; - - // https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html#shutdown-- - virtual void Shutdown() = 0; - - virtual int GetTid(int index) const = 0; -}; - -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_EXECUTOR_H_ diff --git a/cpp/platform_v2/api/future.h b/cpp/platform_v2/api/future.h deleted file mode 100644 index b3ec2f0f..00000000 --- a/cpp/platform_v2/api/future.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef PLATFORM_V2_API_FUTURE_H_ -#define PLATFORM_V2_API_FUTURE_H_ - -#include "platform_v2/base/exception.h" -#include "absl/time/clock.h" - -namespace location { -namespace nearby { -namespace api { - -// A Future represents the result of an asynchronous computation. -// -// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html -template -class Future { - public: - virtual ~Future() = default; - - // throws Exception::kInterrupted, Exception::kExecution - virtual ExceptionOr Get() = 0; - - // throws Exception::kInterrupted, Exception::kExecution - // throws Exception::kTimeout if timeout is exceeded while waiting for - // result. - virtual ExceptionOr Get(absl::Duration timeout) = 0; -}; - -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_FUTURE_H_ diff --git a/cpp/platform_v2/api/input_file.h b/cpp/platform_v2/api/input_file.h deleted file mode 100644 index cc8730ee..00000000 --- a/cpp/platform_v2/api/input_file.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef PLATFORM_V2_API_INPUT_FILE_H_ -#define PLATFORM_V2_API_INPUT_FILE_H_ - -#include - -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/exception.h" -#include "platform_v2/base/input_stream.h" - -namespace location { -namespace nearby { -namespace api { - -// An InputFile represents a readable file on the system. -class InputFile : public InputStream { - public: - ~InputFile() override = default; - virtual std::string GetFilePath() const = 0; - virtual std::int64_t GetTotalSize() const = 0; -}; - -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_INPUT_FILE_H_ diff --git a/cpp/platform_v2/api/listenable_future.h b/cpp/platform_v2/api/listenable_future.h deleted file mode 100644 index af38e8a5..00000000 --- a/cpp/platform_v2/api/listenable_future.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef PLATFORM_V2_API_LISTENABLE_FUTURE_H_ -#define PLATFORM_V2_API_LISTENABLE_FUTURE_H_ - -#include -#include - -#include "platform_v2/api/executor.h" -#include "platform_v2/api/future.h" -#include "platform_v2/base/exception.h" -#include "platform_v2/base/runnable.h" - -namespace location { -namespace nearby { -namespace api { - -// A Future that accepts completion listeners. -// -// https://guava.dev/releases/20.0/api/docs/com/google/common/util/concurrent/ListenableFuture.html -template -class ListenableFuture : public Future { - public: - ~ListenableFuture() override = default; - - virtual void AddListener(Runnable runnable, - Executor* executor) = 0; -}; - -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_LISTENABLE_FUTURE_H_ diff --git a/cpp/platform_v2/api/output_file.h b/cpp/platform_v2/api/output_file.h deleted file mode 100644 index 2e694b05..00000000 --- a/cpp/platform_v2/api/output_file.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef PLATFORM_V2_API_OUTPUT_FILE_H_ -#define PLATFORM_V2_API_OUTPUT_FILE_H_ - -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/exception.h" -#include "platform_v2/base/output_stream.h" - -namespace location { -namespace nearby { -namespace api { - -// An OutputFile represents a writable file on the system. -class OutputFile : public OutputStream { - public: - ~OutputFile() override = default; -}; - -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_OUTPUT_FILE_H_ diff --git a/cpp/platform_v2/api/platform.h b/cpp/platform_v2/api/platform.h deleted file mode 100644 index eee8bfad..00000000 --- a/cpp/platform_v2/api/platform.h +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef PLATFORM_V2_API_PLATFORM_H_ -#define PLATFORM_V2_API_PLATFORM_H_ - -#include -#include -#include - -#include "platform_v2/api/atomic_boolean.h" -#include "platform_v2/api/atomic_reference.h" -#include "platform_v2/api/ble.h" -#include "platform_v2/api/ble_v2.h" -#include "platform_v2/api/bluetooth_adapter.h" -#include "platform_v2/api/bluetooth_classic.h" -#include "platform_v2/api/condition_variable.h" -#include "platform_v2/api/count_down_latch.h" -#include "platform_v2/api/crypto.h" -#include "platform_v2/api/input_file.h" -#include "platform_v2/api/log_message.h" -#include "platform_v2/api/mutex.h" -#include "platform_v2/api/output_file.h" -#include "platform_v2/api/scheduled_executor.h" -#include "platform_v2/api/server_sync.h" -#include "platform_v2/api/settable_future.h" -#include "platform_v2/api/submittable_executor.h" -#include "platform_v2/api/system_clock.h" -#include "platform_v2/api/webrtc.h" -#include "platform_v2/api/wifi.h" -#include "platform_v2/api/wifi_lan.h" -#include "platform_v2/base/payload_id.h" -#include "absl/strings/string_view.h" - -namespace location { -namespace nearby { -namespace api { - -// API rework notes: -// https://docs.google.com/spreadsheets/d/1erZNkX7pX8s5jWTHdxgjntxTMor3BGiY2H_fC_ldtoQ/edit#gid=381357998 -class ImplementationPlatform { - public: - // General platform support: - // - atomic variables (boolean, and any other copyable type) - // - synchronization primitives: - // - mutex (regular, and recursive) - // - condition variable (must work with regular mutex only) - // - Future : to synchronize on Callable scheduled to execute. - // - CountDownLatch : to ensure at least N threads are waiting. - // - file I/O - // - Logging - - // Atomics: - // ======= - - // Atomic boolean: special case. Uses native platform atomics. - // Does not use locking. - // Does not use dynamic memory allocations in operations. - static std::unique_ptr CreateAtomicBoolean(bool initial_value); - - // Supports enums and integers up to 32-bit. - // Does not use locking, if platform supports 32-bit atimics natively. - // Does not use dynamic memory allocations in operations. - static std::unique_ptr CreateAtomicUint32(std::uint32_t value); - - static std::unique_ptr CreateCountDownLatch( - std::int32_t count); - static std::unique_ptr CreateMutex(Mutex::Mode mode); - static std::unique_ptr CreateConditionVariable( - Mutex* mutex); - static std::unique_ptr CreateInputFile(PayloadId payload_id, - std::int64_t total_size); - static std::unique_ptr CreateOutputFile(PayloadId payload_id); - static std::unique_ptr CreateLogMessage( - const char* file, int line, LogMessage::Severity severity); - - // Java-like Executors - static std::unique_ptr CreateSingleThreadExecutor(); - static std::unique_ptr CreateMultiThreadExecutor( - std::int32_t max_concurrency); - static std::unique_ptr CreateScheduledExecutor(); - - // Protocol implementations, domain-specific support - static std::unique_ptr CreateBluetoothAdapter(); - static std::unique_ptr CreateBluetoothClassicMedium( - BluetoothAdapter&); - static std::unique_ptr CreateBleMedium(BluetoothAdapter&); - static std::unique_ptr CreateBleV2Medium( - BluetoothAdapter&); - static std::unique_ptr CreateServerSyncMedium(); - static std::unique_ptr CreateWifiMedium(); - static std::unique_ptr CreateWifiLanMedium(); - static std::unique_ptr CreateWebRtcMedium(); -}; - -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_PLATFORM_H_ diff --git a/cpp/platform_v2/api/scheduled_executor.h b/cpp/platform_v2/api/scheduled_executor.h deleted file mode 100644 index a19369e4..00000000 --- a/cpp/platform_v2/api/scheduled_executor.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef PLATFORM_V2_API_SCHEDULED_EXECUTOR_H_ -#define PLATFORM_V2_API_SCHEDULED_EXECUTOR_H_ - -#include -#include -#include - -#include "platform_v2/api/cancelable.h" -#include "platform_v2/api/executor.h" -#include "platform_v2/base/runnable.h" -#include "absl/time/time.h" - -namespace location { -namespace nearby { -namespace api { - -// An Executor that can schedule commands to run after a given delay, or to -// execute periodically. -// -// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledExecutorService.html -class ScheduledExecutor : public Executor { - public: - ~ScheduledExecutor() override = default; - // Cancelable is kept both in the executor context, and in the caller context. - // We want Cancelable to live until both caller and executor are done with it. - // Exclusive ownership model does not work for this case; - // using std:shared_ptr<> instead if std::unique_ptr<>. - virtual std::shared_ptr Schedule(Runnable&& runnable, - absl::Duration duration) = 0; -}; - -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_SCHEDULED_EXECUTOR_H_ diff --git a/cpp/platform_v2/api/server_sync.h b/cpp/platform_v2/api/server_sync.h deleted file mode 100644 index 4e9f1b90..00000000 --- a/cpp/platform_v2/api/server_sync.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef PLATFORM_V2_API_SERVER_SYNC_H_ -#define PLATFORM_V2_API_SERVER_SYNC_H_ - -#include - -#include "platform_v2/base/byte_array.h" -#include "absl/strings/string_view.h" - -namespace location { -namespace nearby { -namespace api { - -// Abstraction that represents a Nearby endpoint exchanging data through -// ServerSync Medium. -class ServerSyncDevice { - public: - virtual ~ServerSyncDevice() = default; - - virtual std::string GetName() const = 0; - virtual std::string GetGuid() const = 0; - virtual std::string GetOwnGuid() const = 0; -}; - -// Container of operations that can be performed over the Chrome Sync medium. -class ServerSyncMedium { - public: - virtual ~ServerSyncMedium() = default; - - virtual bool StartAdvertising(absl::string_view service_id, - absl::string_view endpoint_id, - const ByteArray& endpoint_info) = 0; - virtual void StopAdvertising(absl::string_view service_id) = 0; - - class DiscoveredDeviceCallback { - public: - virtual ~DiscoveredDeviceCallback() = default; - - // Called on a new ServerSyncDevice discovery. - virtual void OnDeviceDiscovered(ServerSyncDevice* device, - absl::string_view service_id, - absl::string_view endpoint_id, - const ByteArray& endpoint_info) = 0; - // Called when ServerSyncDevice is no longer reachable. - virtual void OnDeviceLost(ServerSyncDevice* device, - absl::string_view service_id) = 0; - }; - - // Returns true once the Chrome Sync scan has been initiated. - virtual bool StartDiscovery( - absl::string_view service_id, - const DiscoveredDeviceCallback& discovered_device_callback) = 0; - // Returns true once Chrome Sync scan for service_id is well and truly - // stopped; after this returns, there must be no more invocations of the - // DiscoveredDeviceCallback passed in to startScanning() for service_id. - virtual void StopDiscovery(absl::string_view service_id) = 0; -}; - -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_SERVER_SYNC_H_ diff --git a/cpp/platform_v2/api/settable_future.h b/cpp/platform_v2/api/settable_future.h deleted file mode 100644 index db921ff5..00000000 --- a/cpp/platform_v2/api/settable_future.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef PLATFORM_V2_API_SETTABLE_FUTURE_H_ -#define PLATFORM_V2_API_SETTABLE_FUTURE_H_ - -#include "platform_v2/api/listenable_future.h" -#include "platform_v2/base/exception.h" - -namespace location { -namespace nearby { -namespace api { - -// A SettableFuture is a type of Future whose result can be set. -// -// https://google.github.io/guava/releases/20.0/api/docs/com/google/common/util/concurrent/SettableFuture.html -template -class SettableFuture : public ListenableFuture { - public: - ~SettableFuture() override = default; - - // Completes the future successfully. The value is returned to any waiters. - // Returns true, if value was set. - // Returns false, if Future is already in "done" state. - virtual bool Set(T value) = 0; - - // Completes the future unsuccessfully. The exception value is returned to any - // waiters. - // Returns true, if exception was set. - // Returns false, if Future is already in "done" state. - virtual bool SetException(Exception exception) = 0; -}; - -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_SETTABLE_FUTURE_H_ diff --git a/cpp/platform_v2/api/submittable_executor.h b/cpp/platform_v2/api/submittable_executor.h deleted file mode 100644 index 542e7fd1..00000000 --- a/cpp/platform_v2/api/submittable_executor.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef PLATFORM_V2_API_SUBMITTABLE_EXECUTOR_H_ -#define PLATFORM_V2_API_SUBMITTABLE_EXECUTOR_H_ - -#include -#include - -#include "platform_v2/api/executor.h" -#include "platform_v2/api/future.h" -#include "platform_v2/base/runnable.h" - -namespace location { -namespace nearby { -namespace api { - -// Main interface to be used by platform as a base class for -// - MultiThreadExecutorWrapper -// - SingleThreadExecutorWrapper -// Platform must override bool submit(std::function) method. -class SubmittableExecutor : public Executor { - public: - ~SubmittableExecutor() override = default; - - // Submit a callable (with no delay). - // Returns true, if callable was submitted, false otherwise. - // Callable is not submitted if shutdown is in progress. - virtual bool DoSubmit(Runnable&& wrapped_callable) = 0; -}; - -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_SUBMITTABLE_EXECUTOR_H_ diff --git a/cpp/platform_v2/api/system_clock.h b/cpp/platform_v2/api/system_clock.h deleted file mode 100644 index c805a915..00000000 --- a/cpp/platform_v2/api/system_clock.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef PLATFORM_V2_API_SYSTEM_CLOCK_H_ -#define PLATFORM_V2_API_SYSTEM_CLOCK_H_ - -#include "platform_v2/base/exception.h" -#include "absl/time/clock.h" - -namespace location { -namespace nearby { - -class SystemClock final { - public: - // Initialize global system state. - static void Init(); - // Returns current absolute time. It is guaranteed to be monotonic. - static absl::Time ElapsedRealtime(); - // Pauses current thread for the specified duration. - static Exception Sleep(absl::Duration duration); -}; - -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_SYSTEM_CLOCK_H_ diff --git a/cpp/platform_v2/api/webrtc.h b/cpp/platform_v2/api/webrtc.h deleted file mode 100644 index d07bc699..00000000 --- a/cpp/platform_v2/api/webrtc.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef PLATFORM_V2_API_WEBRTC_H_ -#define PLATFORM_V2_API_WEBRTC_H_ - -#include - -#include "platform_v2/base/byte_array.h" -#include "absl/strings/string_view.h" -#include "webrtc/api/peer_connection_interface.h" - -namespace location { -namespace nearby { -namespace api { - -class WebRtcSignalingMessenger { - public: - using OnSignalingMessageCallback = std::function; - - virtual ~WebRtcSignalingMessenger() = default; - - virtual bool SendMessage(absl::string_view peer_id, - const ByteArray& message) = 0; - - virtual bool StartReceivingMessages(OnSignalingMessageCallback listener) = 0; - virtual void StopReceivingMessages() = 0; -}; - -class WebRtcMedium { - public: - using PeerConnectionCallback = - std::function)>; - - virtual ~WebRtcMedium() = default; - - // Creates and returns a new webrtc::PeerConnectionInterface object via - // |callback|. - virtual void CreatePeerConnection(webrtc::PeerConnectionObserver* observer, - PeerConnectionCallback callback) = 0; - - // Returns a signaling messenger for sending WebRTC signaling messages. - virtual std::unique_ptr GetSignalingMessenger( - absl::string_view self_id) = 0; -}; - -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_WEBRTC_H_ diff --git a/cpp/platform_v2/api/wifi.h b/cpp/platform_v2/api/wifi.h deleted file mode 100644 index 74ddb6f9..00000000 --- a/cpp/platform_v2/api/wifi.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef PLATFORM_V2_API_WIFI_H_ -#define PLATFORM_V2_API_WIFI_H_ - -#include -#include -#include - -#include "absl/strings/string_view.h" - -namespace location { -namespace nearby { -namespace api { - -// Possible authentication types for a WiFi network. -enum class WifiAuthType { - // WiFi Authentication type; either none (non-secured a.k.a. open) link, or - // WPA PSK (WiFi Protected Access PreShared Key), or - // see https://en.wikipedia.org/wiki/Wi-Fi_Protected_Access - // WEP (Wired Equivalent Privacy); - // see https://en.wikipedia.org/wiki/Wired_Equivalent_Privacy - kUnknown = 0, - kOpen = 1, - kWpaPsk = 2, - kWep = 3, -}; - -// Possible statuses of a device's connection to a WiFi network. -enum class WifiConnectionStatus { - kUnknown = 0, - kConnected = 1, - kConnectionFailure = 2, - kAuthFailure = 3, -}; - -// Represents a WiFi network found during a call to WifiMedium#scan(). -class WifiScanResult { - public: - virtual ~WifiScanResult() = default; - - // Gets the SSID of this WiFi network. - virtual std::string GetSsid() const = 0; - // Gets the signal strength of this WiFi network in dBm. - virtual std::int32_t GetSignalStrengthDbm() const = 0; - // Gets the frequency band of this WiFi network in MHz. - virtual std::int32_t GetFrequencyMhz() const = 0; - // Gets the authentication type of this WiFi network. - virtual WifiAuthType GetAuthType() const = 0; -}; - -// Container of operations that can be performed over the WiFi medium. -class WifiMedium { - public: - virtual ~WifiMedium() {} - - class ScanResultCallback { - public: - virtual ~ScanResultCallback() = default; - - virtual void OnScanResults( - const std::vector& scan_results) = 0; - }; - - // Does not take ownership of the passed-in scan_result_callback -- destroying - // that is up to the caller. - virtual bool Scan(const ScanResultCallback& scan_result_callback) = 0; - - // If 'password' is an empty string, none has been provided. Returns - // WifiConnectionStatus::CONNECTED on success, or the appropriate failure code - // otherwise. - virtual WifiConnectionStatus ConnectToNetwork(absl::string_view ssid, - absl::string_view password, - WifiAuthType auth_type) = 0; - - // Blocks until it's certain of there being a connection to the internet, or - // returns false if it fails to do so. - // - // How this method wants to verify said connection is totally up to it (so it - // can feel free to ping whatever server, download whatever resource, etc. - // that it needs to gain confidence that the internet is reachable hereon in). - virtual bool VerifyInternetConnectivity() = 0; - - // Returns the local device's IP address in the IPv4 dotted-quad format. - virtual std::string GetIpAddress() = 0; -}; - -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_WIFI_H_ diff --git a/cpp/platform_v2/api/wifi_lan.h b/cpp/platform_v2/api/wifi_lan.h deleted file mode 100644 index 12a9e423..00000000 --- a/cpp/platform_v2/api/wifi_lan.h +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef PLATFORM_V2_API_WIFI_LAN_H_ -#define PLATFORM_V2_API_WIFI_LAN_H_ - -#include - -#include "platform_v2/base/byte_array.h" -#include "platform_v2/base/input_stream.h" -#include "platform_v2/base/listeners.h" -#include "platform_v2/base/output_stream.h" -#include "absl/strings/string_view.h" - -namespace location { -namespace nearby { -namespace api { - -// Opaque wrapper over a WifiLan service which contains packed -// |WifiLanServiceInfo| string name. -class WifiLanService { - public: - virtual ~WifiLanService() = default; - - virtual std::string GetName() const = 0; - - // Returns the local device's as a pair. - // IP address is in byte sequence, in network order. - virtual std::pair GetServiceAddress() const = 0; -}; - -class WifiLanSocket { - public: - virtual ~WifiLanSocket() = default; - - // Returns the InputStream of the WifiLanSocket. - // On error, returned stream will report Exception::kIo on any operation. - // - // The returned object is not owned by the caller, and can be invalidated once - // the WifiLanSocket object is destroyed. - virtual InputStream& GetInputStream() = 0; - - // Returns the OutputStream of the WifiLanSocket. - // On error, returned stream will report Exception::kIo on any operation. - // - // The returned object is not owned by the caller, and can be invalidated once - // the WifiLanSocket object is destroyed. - virtual OutputStream& GetOutputStream() = 0; - - // Returns Exception::kIo on error, Exception::kSuccess otherwise. - virtual Exception Close() = 0; - - // Returns valid WifiLanService pointer if there is a connection, and - // nullptr otherwise. - virtual WifiLanService* GetRemoteWifiLanService() = 0; -}; - -// Container of operations that can be performed over the WifiLan medium. -class WifiLanMedium { - public: - virtual ~WifiLanMedium() = default; - - virtual bool StartAdvertising( - const std::string& service_id, - const std::string& wifi_lan_service_info_name) = 0; - virtual bool StopAdvertising(const std::string& service_id) = 0; - - // Callback that is invoked when a discovered service is found or lost. - struct DiscoveredServiceCallback { - std::function - service_discovered_cb = - DefaultCallback(); - std::function - service_lost_cb = - DefaultCallback(); - }; - - // Returns true once the WifiLan discovery has been initiated. - virtual bool StartDiscovery(const std::string& service_id, - DiscoveredServiceCallback callback) = 0; - - // Returns true once WifiLan discovery for service_id is well and truly - // stopped; after this returns, there must be no more invocations of the - // DiscoveredServiceCallback passed in to StartDiscovery() for service_id. - virtual bool StopDiscovery(const std::string& service_id) = 0; - - // Callback that is invoked when a new connection is accepted. - struct AcceptedConnectionCallback { - std::function - accepted_cb = DefaultCallback(); - }; - - // Returns true once WifiLan socket connection requests to service_id can be - // accepted. - virtual bool StartAcceptingConnections( - const std::string& service_id, AcceptedConnectionCallback callback) = 0; - virtual bool StopAcceptingConnections(const std::string& service_id) = 0; - - // Connects to a WifiLan service. - // On success, returns a new WifiLanSocket. - // On error, returns nullptr. - virtual std::unique_ptr Connect( - WifiLanService& service, const std::string& service_id) = 0; - - virtual WifiLanService* FindRemoteService(const std::string& ip_address, - int port) = 0; -}; - -} // namespace api -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_API_WIFI_LAN_H_ diff --git a/cpp/platform_v2/config/config.h b/cpp/platform_v2/config/config.h deleted file mode 100644 index 2efef96b..00000000 --- a/cpp/platform_v2/config/config.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef PLATFORM_V2_CONFIG_CONFIG_H_ -#define PLATFORM_V2_CONFIG_CONFIG_H_ - -// Clients can modify this file to customize the Nearby C++ codebase as per -// their particular constraints and environments. - -// Note: Every entry in this file should conform to the following format, to -// give precedence to command-line options (-D) that set these symbols: -// -// #ifndef XXX -// #define XXX 0/1 -// #endif - -#ifndef NEARBY_USE_STD_STRING -#define NEARBY_USE_STD_STRING 0 -#endif - -#ifndef NEARBY_USE_RTTI -#define NEARBY_USE_RTTI 1 -#endif - -#endif // PLATFORM_V2_CONFIG_CONFIG_H_ diff --git a/cpp/platform_v2/config/string.h b/cpp/platform_v2/config/string.h deleted file mode 100644 index 10db45ef..00000000 --- a/cpp/platform_v2/config/string.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef PLATFORM_V2_CONFIG_STRING_H_ -#define PLATFORM_V2_CONFIG_STRING_H_ - -#include - -#include "platform_v2/config/config.h" - -#if NEARBY_USE_STD_STRING -using std::string; -#endif - -#endif // PLATFORM_V2_CONFIG_STRING_H_ diff --git a/cpp/platform_v2/impl/g3/BUILD b/cpp/platform_v2/impl/g3/BUILD deleted file mode 100644 index 53a8fd8d..00000000 --- a/cpp/platform_v2/impl/g3/BUILD +++ /dev/null @@ -1,110 +0,0 @@ -cc_library( - name = "types", - testonly = True, - srcs = [ - "log_message.cc", - "scheduled_executor.cc", - "system_clock.cc", - ], - hdrs = [ - "atomic_boolean.h", - "atomic_reference.h", - "condition_variable.h", - "count_down_latch.h", - "log_message.h", - "multi_thread_executor.h", - "mutex.h", - "pipe.h", - "scheduled_executor.h", - "single_thread_executor.h", - ], - visibility = ["//visibility:private"], - deps = [ - "//base", - "//platform_v2/api:platform", - "//platform_v2/api:types", - "//platform_v2/base", - "//platform_v2/base:util", - "//platform_v2/impl/shared:posix_mutex", - "//absl/base:core_headers", - "//absl/synchronization", - "//absl/time", - "//thread", - ], -) - -cc_library( - name = "comm", - testonly = True, - srcs = [ - "ble.cc", - "bluetooth_adapter.cc", - "bluetooth_classic.cc", - "webrtc.cc", - "wifi_lan.cc", - ], - hdrs = [ - "ble.h", - "bluetooth_adapter.h", - "bluetooth_classic.h", - "webrtc.h", - "wifi_lan.h", - ], - visibility = ["//visibility:private"], - deps = [ - ":types", - "//platform_v2/api:comm", - "//platform_v2/base", - "//platform_v2/base:logging", - "//platform_v2/base:test_util", - "//absl/base:core_headers", - "//absl/container:flat_hash_map", - "//absl/container:flat_hash_set", - "//absl/strings", - "//absl/synchronization", - "//webrtc/api:create_peerconnection_factory", #buildcleaner: keep - "//webrtc/api:libjingle_peerconnection_api", - "//webrtc/api/task_queue:default_task_queue_factory", - ], -) - -cc_library( - name = "crypto", - testonly = True, - srcs = [ - "crypto.cc", - ], - visibility = ["//visibility:private"], - deps = [ - "//platform_v2/api:types", - "//platform_v2/base", - "//absl/strings", - "//openssl:crypto", - ], -) - -cc_library( - name = "g3", - testonly = True, - srcs = [ - "platform.cc", - ], - visibility = [ - "//core_v2:__subpackages__", - "//platform_v2:__subpackages__", - ], - deps = [ - ":comm", - ":crypto", # build_cleaner: keep - ":types", - "//platform_v2/api:comm", - "//platform_v2/api:platform", - "//platform_v2/api:types", - "//platform_v2/base:test_util", - "//platform_v2/impl/shared:file", - "//absl/base:core_headers", - "//absl/memory", - "//absl/strings", - "//absl/time", - ], -) diff --git a/cpp/platform_v2/impl/g3/platform.cc b/cpp/platform_v2/impl/g3/platform.cc deleted file mode 100644 index 8392e7d2..00000000 --- a/cpp/platform_v2/impl/g3/platform.cc +++ /dev/null @@ -1,159 +0,0 @@ -#include "platform_v2/api/platform.h" - -#include -#include - -#include "platform_v2/api/atomic_boolean.h" -#include "platform_v2/api/atomic_reference.h" -#include "platform_v2/api/ble_v2.h" -#include "platform_v2/api/bluetooth_adapter.h" -#include "platform_v2/api/bluetooth_classic.h" -#include "platform_v2/api/condition_variable.h" -#include "platform_v2/api/count_down_latch.h" -#include "platform_v2/api/log_message.h" -#include "platform_v2/api/mutex.h" -#include "platform_v2/api/scheduled_executor.h" -#include "platform_v2/api/server_sync.h" -#include "platform_v2/api/submittable_executor.h" -#include "platform_v2/api/webrtc.h" -#include "platform_v2/api/wifi.h" -#include "platform_v2/base/medium_environment.h" -#include "platform_v2/impl/g3/atomic_boolean.h" -#include "platform_v2/impl/g3/atomic_reference.h" -#include "platform_v2/impl/g3/ble.h" -#include "platform_v2/impl/g3/bluetooth_adapter.h" -#include "platform_v2/impl/g3/bluetooth_classic.h" -#include "platform_v2/impl/g3/condition_variable.h" -#include "platform_v2/impl/g3/count_down_latch.h" -#include "platform_v2/impl/g3/log_message.h" -#include "platform_v2/impl/g3/multi_thread_executor.h" -#include "platform_v2/impl/g3/mutex.h" -#include "platform_v2/impl/g3/scheduled_executor.h" -#include "platform_v2/impl/g3/single_thread_executor.h" -#include "platform_v2/impl/g3/webrtc.h" -#include "platform_v2/impl/g3/wifi_lan.h" -#include "platform_v2/impl/shared/file.h" -#include "absl/base/integral_types.h" -#include "absl/memory/memory.h" -#include "absl/strings/str_cat.h" -#include "absl/time/time.h" - -namespace location { -namespace nearby { -namespace api { - -namespace { -std::string GetPayloadPath(PayloadId payload_id) { - return absl::StrCat("/tmp/", payload_id); -} -} // namespace - -int GetCurrentTid() { - const LiveThread* my = Thread_GetMyLiveThread(); - return LiveThread_Pthread_TID(my); -} - -std::unique_ptr -ImplementationPlatform::CreateSingleThreadExecutor() { - return absl::make_unique(); -} - -std::unique_ptr -ImplementationPlatform::CreateMultiThreadExecutor(int max_concurrency) { - return absl::make_unique(max_concurrency); -} - -std::unique_ptr -ImplementationPlatform::CreateScheduledExecutor() { - return absl::make_unique(); -} - -std::unique_ptr -ImplementationPlatform::CreateAtomicUint32(std::uint32_t value) { - return absl::make_unique(value); -} - -std::unique_ptr -ImplementationPlatform::CreateBluetoothAdapter() { - return absl::make_unique(); -} - -std::unique_ptr ImplementationPlatform::CreateCountDownLatch( - std::int32_t count) { - return absl::make_unique(count); -} - -std::unique_ptr ImplementationPlatform::CreateAtomicBoolean( - bool initial_value) { - return absl::make_unique(initial_value); -} - -std::unique_ptr ImplementationPlatform::CreateInputFile( - PayloadId payload_id, std::int64_t total_size) { - return absl::make_unique(GetPayloadPath(payload_id), - total_size); -} - -std::unique_ptr ImplementationPlatform::CreateOutputFile( - PayloadId payload_id) { - return absl::make_unique(GetPayloadPath(payload_id)); -} - -std::unique_ptr ImplementationPlatform::CreateLogMessage( - const char* file, int line, LogMessage::Severity severity) { - return absl::make_unique(file, line, severity); -} - -std::unique_ptr -ImplementationPlatform::CreateBluetoothClassicMedium( - api::BluetoothAdapter& adapter) { - return absl::make_unique(adapter); -} - -std::unique_ptr ImplementationPlatform::CreateBleMedium( - api::BluetoothAdapter& adapter) { - return absl::make_unique(adapter); -} - -std::unique_ptr ImplementationPlatform::CreateBleV2Medium( - api::BluetoothAdapter& adapter) { - return std::unique_ptr(); -} - -std::unique_ptr -ImplementationPlatform::CreateServerSyncMedium() { - return std::unique_ptr(/*new ServerSyncMediumImpl()*/); -} - -std::unique_ptr ImplementationPlatform::CreateWifiMedium() { - return std::unique_ptr(); -} - -std::unique_ptr ImplementationPlatform::CreateWifiLanMedium() { - return absl::make_unique(); -} - -std::unique_ptr ImplementationPlatform::CreateWebRtcMedium() { - if (MediumEnvironment::Instance().GetEnvironmentConfig().webrtc_enabled) { - return absl::make_unique(); - } else { - return nullptr; - } -} - -std::unique_ptr ImplementationPlatform::CreateMutex(Mutex::Mode mode) { - if (mode == Mutex::Mode::kRecursive) - return absl::make_unique(); - else - return absl::make_unique(mode == Mutex::Mode::kRegular); -} - -std::unique_ptr -ImplementationPlatform::CreateConditionVariable(Mutex* mutex) { - return std::unique_ptr( - new g3::ConditionVariable(static_cast(mutex))); -} - -} // namespace api -} // namespace nearby -} // namespace location diff --git a/cpp/platform_v2/impl/ios/BUILD b/cpp/platform_v2/impl/ios/BUILD deleted file mode 100644 index fa133022..00000000 --- a/cpp/platform_v2/impl/ios/BUILD +++ /dev/null @@ -1,56 +0,0 @@ -objc_library( - name = "types", - srcs = [ - "log_message.mm", - "scheduled_executor.mm", - ], - hdrs = [ - "atomic_boolean.h", - "atomic_reference.h", - "condition_variable.h", - "count_down_latch.h", - "log_message.h", - "multi_thread_executor.h", - "mutex.h", - "scheduled_executor.h", - "single_thread_executor.h", - ], - visibility = [ - "//platform_v2/impl/ios:__pkg__", - ], - deps = [ - "//base", - "//platform_v2/api:platform", - "//platform_v2/api:types", - "//platform_v2/base", - "//platform_v2/base:util", - "//platform_v2/impl/shared:posix_mutex", - "//absl/base:core_headers", - "//absl/synchronization", - "//absl/time", - "//thread", - ], -) - -objc_library( - name = "ios", - srcs = [ - "platform.mm", - ], - visibility = [ - "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", - "//core_v2:__subpackages__", - "//platform_v2:__subpackages__", - ], - deps = [ - ":types", - "//platform_v2/api:comm", - "//platform_v2/api:platform", - "//platform_v2/api:types", - "//platform_v2/impl/shared:file", - "//absl/base:core_headers", - "//absl/memory", - "//absl/strings", - "//absl/time", - ], -) diff --git a/cpp/platform_v2/impl/shared/BUILD b/cpp/platform_v2/impl/shared/BUILD deleted file mode 100644 index 87115901..00000000 --- a/cpp/platform_v2/impl/shared/BUILD +++ /dev/null @@ -1,54 +0,0 @@ -cc_library( - name = "posix_mutex", - srcs = [ - "posix_mutex.cc", - ], - hdrs = [ - "posix_mutex.h", - ], - visibility = [ - "//platform_v2/impl:__subpackages__", - ], - deps = ["//platform_v2/api:types"], -) - -cc_library( - name = "posix_condition_variable", - srcs = [ - "posix_condition_variable.cc", - ], - hdrs = [ - "posix_condition_variable.h", - ], - visibility = ["//visibility:private"], - deps = [ - ":posix_mutex", - "//platform_v2/api:types", - ], -) - -cc_library( - name = "file", - srcs = ["file.cc"], - hdrs = ["file.h"], - visibility = [ - "//platform_v2/impl:__subpackages__", - ], - deps = [ - "//platform_v2/api:types", - "//platform_v2/base", - "//absl/strings", - ], -) - -cc_test( - name = "file_test", - srcs = ["file_test.cc"], - deps = [ - ":file", - "//file/util:temp_path", - "//platform_v2/base", - "//testing/base/public:gunit_main", - "//absl/strings", - ], -) diff --git a/cpp/platform_v2/impl/shared/posix_condition_variable.cc b/cpp/platform_v2/impl/shared/posix_condition_variable.cc deleted file mode 100644 index 6d734b0f..00000000 --- a/cpp/platform_v2/impl/shared/posix_condition_variable.cc +++ /dev/null @@ -1,30 +0,0 @@ -#include "platform_v2/impl/shared/posix_condition_variable.h" - -namespace location { -namespace nearby { -namespace posix { - -ConditionVariable::ConditionVariable(Mutex* mutex) - : mutex_(mutex), attr_(), cond_() { - pthread_condattr_init(&attr_); - - pthread_cond_init(&cond_, &attr_); -} - -ConditionVariable::~ConditionVariable() { - pthread_cond_destroy(&cond_); - - pthread_condattr_destroy(&attr_); -} - -void ConditionVariable::Notify() { pthread_cond_broadcast(&cond_); } - -Exception ConditionVariable::Wait() { - pthread_cond_wait(&cond_, &(mutex_->mutex_)); - - return {Exception::kSuccess}; -} - -} // namespace posix -} // namespace nearby -} // namespace location diff --git a/cpp/platform_v2/impl/shared/posix_condition_variable.h b/cpp/platform_v2/impl/shared/posix_condition_variable.h deleted file mode 100644 index 25e3e756..00000000 --- a/cpp/platform_v2/impl/shared/posix_condition_variable.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef PLATFORM_V2_IMPL_SHARED_POSIX_CONDITION_VARIABLE_H_ -#define PLATFORM_V2_IMPL_SHARED_POSIX_CONDITION_VARIABLE_H_ - -#include - -#include "platform_v2/api/condition_variable.h" -#include "platform_v2/impl/shared/posix_mutex.h" - -namespace location { -namespace nearby { -namespace posix { - -class ConditionVariable : public api::ConditionVariable { - public: - explicit ConditionVariable(Mutex* mutex); - ~ConditionVariable() override; - - void Notify() override; - Exception Wait() override; - - private: - Mutex* mutex_; - pthread_condattr_t attr_; - pthread_cond_t cond_; -}; - -} // namespace posix -} // namespace nearby -} // namespace location - -#endif // PLATFORM_V2_IMPL_SHARED_POSIX_CONDITION_VARIABLE_H_ diff --git a/cpp/platform_v2/public/crypto.h b/cpp/platform_v2/public/crypto.h deleted file mode 100644 index f12dc177..00000000 --- a/cpp/platform_v2/public/crypto.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef PLATFORM_V2_PUBLIC_CRYPTO_H_ -#define PLATFORM_V2_PUBLIC_CRYPTO_H_ - -#include "platform_v2/api/crypto.h" - -#endif // PLATFORM_V2_PUBLIC_CRYPTO_H_ diff --git a/cpp/platform_v2/public/logging.h b/cpp/platform_v2/public/logging.h deleted file mode 100644 index cde3df05..00000000 --- a/cpp/platform_v2/public/logging.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef PLATFORM_V2_PUBLIC_LOGGING_H_ -#define PLATFORM_V2_PUBLIC_LOGGING_H_ - -#include "platform_v2/base/logging.h" - -#endif // PLATFORM_V2_PUBLIC_LOGGING_H_ diff --git a/cpp/platform_v2/public/system_clock.h b/cpp/platform_v2/public/system_clock.h deleted file mode 100644 index f1b95bad..00000000 --- a/cpp/platform_v2/public/system_clock.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef PLATFORM_V2_PUBLIC_SYSTEM_CLOCK_H_ -#define PLATFORM_V2_PUBLIC_SYSTEM_CLOCK_H_ - -#include "platform_v2/api/system_clock.h" - -#endif // PLATFORM_V2_PUBLIC_SYSTEM_CLOCK_H_ diff --git a/proto/bootstrap_enums.proto b/proto/bootstrap_enums.proto index a36fd12f..1caf01d9 100644 --- a/proto/bootstrap_enums.proto +++ b/proto/bootstrap_enums.proto @@ -5,6 +5,7 @@ package location.nearby.proto; import "logs/proto/logs_annotations/logs_annotations.proto"; option optimize_for = LITE_RUNTIME; +option jspb_use_correct_proto2_semantics = false; // go/jspb-correct-proto2 option (logs_proto.file_not_used_for_logging_except_enums) = true; option java_api_version = 2; option java_package = "com.google.location.nearby.proto"; diff --git a/proto/connections/BUILD b/proto/connections/BUILD index c7c295c2..92fcc9bf 100644 --- a/proto/connections/BUILD +++ b/proto/connections/BUILD @@ -6,7 +6,9 @@ proto_library( "offline_wire_formats.proto", ], cc_api_version = 2, - visibility = ["//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__"], + visibility = [ + "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", + ], ) java_lite_proto_library( @@ -30,7 +32,10 @@ portable_proto_library( proto_deps = [ ":offline_wire_formats_proto", ], - visibility = ["//location/nearby/connections:__subpackages__"], + visibility = [ + "//location/nearby/connections:__subpackages__", + "//platform:__subpackages__", + ], ) filegroup( diff --git a/proto/discovery_enums.proto b/proto/discovery_enums.proto index cc095756..426393cf 100644 --- a/proto/discovery_enums.proto +++ b/proto/discovery_enums.proto @@ -5,6 +5,7 @@ package location.nearby.proto; import "logs/proto/logs_annotations/logs_annotations.proto"; option optimize_for = LITE_RUNTIME; +option jspb_use_correct_proto2_semantics = false; // go/jspb-correct-proto2 option (logs_proto.file_not_used_for_logging_except_enums) = true; option java_api_version = 2; option java_package = "com.google.location.nearby.proto"; diff --git a/proto/error_code_enums.proto b/proto/error_code_enums.proto index 6ea1f745..290517b0 100644 --- a/proto/error_code_enums.proto +++ b/proto/error_code_enums.proto @@ -219,6 +219,15 @@ enum StartListeningIncomingConnectionError { // Next ID :36 } +// The error for event STOP_LISTENING_INCOMING_CONNECTION. The range between 31 +// and 99. +enum StopListeningIncomingConnectionError { + // System error, failed to stop accepting the incoming connection + STOP_ACCEPTING_CONNECTION_FAILED = 31; + + // Next ID :32 +} + // The error for event CONNECT. The range between 31 and 99. enum ConnectError { // Network error, failed to connect to remote device because we lost the @@ -413,4 +422,5 @@ enum Description { INVALID_WEBRTC_STATE = 146; NULL_DATA_CHANNEL = 147; CREATE_OFFER_FAILED = 148; + CLOSE_SERVER_SOCKET_FAILED = 149; } diff --git a/proto/magic_pair_enums.proto b/proto/magic_pair_enums.proto index 8cd616ec..5269b8cb 100644 --- a/proto/magic_pair_enums.proto +++ b/proto/magic_pair_enums.proto @@ -5,6 +5,7 @@ package location.nearby.proto; import "logs/proto/logs_annotations/logs_annotations.proto"; option optimize_for = LITE_RUNTIME; +option jspb_use_correct_proto2_semantics = false; // go/jspb-correct-proto2 option (logs_proto.file_not_used_for_logging_except_enums) = true; option java_api_version = 2; option java_package = "com.google.location.nearby.proto"; diff --git a/proto/nearby_client_enums.proto b/proto/nearby_client_enums.proto index 90c01688..093ef17b 100644 --- a/proto/nearby_client_enums.proto +++ b/proto/nearby_client_enums.proto @@ -5,6 +5,7 @@ package location.nearby.proto; import "logs/proto/logs_annotations/logs_annotations.proto"; option optimize_for = LITE_RUNTIME; +option jspb_use_correct_proto2_semantics = false; // go/jspb-correct-proto2 option (logs_proto.file_not_used_for_logging_except_enums) = true; option java_api_version = 2; option java_package = "com.google.location.nearby.proto";