diff --git a/cpp/core/internal/BUILD b/cpp/core/internal/BUILD index e9d2dd67..f54df70d 100644 --- a/cpp/core/internal/BUILD +++ b/cpp/core/internal/BUILD @@ -8,7 +8,7 @@ cc_library( "loop_runner.cc", "loop_runner.h", "offline_frames.cc", - "offline_frames.h", + "wifi_lan_service_info.cc", ], hdrs = [ "bandwidth_upgrade_handler.h", @@ -40,6 +40,7 @@ cc_library( "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", @@ -57,6 +58,7 @@ cc_library( "service_controller.h", "service_controller_router.cc", "service_controller_router.h", + "wifi_lan_service_info.h", "wifi_lan_upgrade_handler.cc", "wifi_lan_upgrade_handler.h", ], @@ -80,6 +82,18 @@ cc_library( ], ) +cc_test( + name = "base_endpoint_channel_test", + srcs = ["base_endpoint_channel_test.cc"], + deps = [ + ":internal", + "//platform:utils", + "//platform/impl/default", + "//proto:connections_enums_portable_proto", + "//testing/base/public:gunit_main", + ], +) + cc_test( name = "bluetooth_device_name_test", srcs = ["bluetooth_device_name_test.cc"], @@ -100,3 +114,27 @@ cc_test( "//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/port:string", + "//testing/base/public:gunit_main", + ], +) + +cc_test( + name = "offline_frames_test", + srcs = [ + "offline_frames_test.cc", + ], + deps = [ + ":internal", + "//proto/connections:offline_wire_formats_portable_proto", + "//platform:types", + "//testing/base/public:gunit_main", + ], +) diff --git a/cpp/core/internal/base_endpoint_channel.cc b/cpp/core/internal/base_endpoint_channel.cc index e6d288c7..6665a2b5 100644 --- a/cpp/core/internal/base_endpoint_channel.cc +++ b/cpp/core/internal/base_endpoint_channel.cc @@ -49,7 +49,7 @@ ExceptionOr > readExactly(Ptr reader, ScopedPtr > scoped_read_bytes(read_bytes.result()); // In Java, EOFException is a sub-variant of IOException. - if (scoped_read_bytes->size() == 0) { + if (scoped_read_bytes.isNull() || scoped_read_bytes->size() == 0) { return ExceptionOr >(Exception::IO); } @@ -81,6 +81,7 @@ Exception::Value writeInt(Ptr writer, std::int32_t value) { } // namespace +// TODO(b/150763574): Move implementatiopn to header or .inc file. template BaseEndpointChannel::BaseEndpointChannel(const string& channel_name, Ptr reader, diff --git a/cpp/core/internal/base_endpoint_channel_test.cc b/cpp/core/internal/base_endpoint_channel_test.cc new file mode 100644 index 00000000..abdb5dbe --- /dev/null +++ b/cpp/core/internal/base_endpoint_channel_test.cc @@ -0,0 +1,60 @@ +#include "core/internal/base_endpoint_channel.h" + +#include "platform/impl/default/default_platform.h" +#include "platform/pipe.h" +#include "proto/connections_enums.pb.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace location { +namespace nearby { +namespace connections { +namespace { + +class TestPlatform : public DefaultPlatform { + public: + static SystemClock* createSystemClock() { return nullptr; } + + static Ptr createAtomicBoolean(bool initial_value) { + return Ptr(); + } + + template + static Ptr> createAtomicReference(const T& initial_value) { + return Ptr>(); + } +}; + +class TestEndpointChannel : public BaseEndpointChannel { + public: + explicit TestEndpointChannel(Ptr input_stream) + : BaseEndpointChannel("channel", input_stream, Ptr()) {} + + MOCK_METHOD(proto::connections::Medium, getMedium, (), (override)); + MOCK_METHOD(void, closeImpl, (), (override)); +}; + +using SamplePipe = Pipe; + +TEST(BaseEndpointChannelTest, ReadAfterInputStreamClosed) { + auto pipe = MakeRefCountedPtr(new SamplePipe()); + ScopedPtr> input_stream(SamplePipe::createInputStream(pipe)); + ScopedPtr> output_stream( + SamplePipe::createOutputStream(pipe)); + + TestEndpointChannel test_channel(input_stream.get()); + + // 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> result = test_channel.read(); + + ASSERT_FALSE(result.ok()); + ASSERT_EQ(Exception::IO, result.exception()); +} + +} // namespace +} // namespace connections +} // namespace nearby +} // namespace location diff --git a/cpp/core/internal/base_pcp_handler.cc b/cpp/core/internal/base_pcp_handler.cc index 84e736f6..e885e42c 100644 --- a/cpp/core/internal/base_pcp_handler.cc +++ b/cpp/core/internal/base_pcp_handler.cc @@ -701,7 +701,10 @@ BasePCPHandler::~BasePCPHandler() { // Unregister ourselves from the IncomingOfflineFrameProcessors. endpoint_manager_->unregisterIncomingOfflineFrameProcessor( - V1Frame::CONNECTION_RESPONSE, MakePtr(this)); + V1Frame::CONNECTION_RESPONSE, + std::static_pointer_cast< + typename EndpointManager::IncomingOfflineFrameProcessor>( + self_)); encryption_runner_.destroy(); @@ -747,7 +750,7 @@ Status::Value BasePCPHandler::startAdvertising( ScopedPtr>> result( runOnPCPHandlerThread( MakePtr(new base_pcp_handler::StartAdvertisingCallable( - MakePtr(this), client_proxy, service_id, local_endpoint_name, + self_, client_proxy, service_id, local_endpoint_name, advertising_options, connection_lifecycle_listener)))); return waitForResult("startAdvertising(" + local_endpoint_name + ")", client_proxy->getClientId(), result.get()); @@ -759,7 +762,7 @@ void BasePCPHandler::stopAdvertising( ScopedPtr> latch(Platform::createCountDownLatch(1)); runOnPCPHandlerThread( MakePtr(new base_pcp_handler::StopAdvertisingRunnable( - MakePtr(this), client_proxy, latch.get()))); + self_, client_proxy, latch.get()))); waitForLatch("stopAdvertising", latch.get()); } @@ -771,7 +774,7 @@ Status::Value BasePCPHandler::startDiscovery( ScopedPtr>> result( runOnPCPHandlerThread( MakePtr(new base_pcp_handler::StartDiscoveryCallable( - MakePtr(this), client_proxy, service_id, discovery_options, + self_, client_proxy, service_id, discovery_options, discovery_listener)))); return waitForResult("startDiscovery(" + service_id + ")", client_proxy->getClientId(), result.get()); @@ -783,7 +786,7 @@ void BasePCPHandler::stopDiscovery( ScopedPtr> latch(Platform::createCountDownLatch(1)); runOnPCPHandlerThread( MakePtr(new base_pcp_handler::StopDiscoveryRunnable( - MakePtr(this), client_proxy, latch.get()))); + self_, client_proxy, latch.get()))); waitForLatch("stopDiscovery", latch.get()); } @@ -796,7 +799,7 @@ Status::Value BasePCPHandler::requestConnection( Platform::template createSettableFuture()); runOnPCPHandlerThread( MakePtr(new base_pcp_handler::RequestConnectionRunnable( - MakePtr(this), client_proxy, local_endpoint_name, endpoint_id, + self_, client_proxy, local_endpoint_name, endpoint_id, connection_lifecycle_listener, result.get()))); return waitForResult("requestConnection(" + endpoint_id + ")", client_proxy->getClientId(), result.get()); @@ -809,7 +812,7 @@ Status::Value BasePCPHandler::acceptConnection( ScopedPtr>> result( runOnPCPHandlerThread( MakePtr(new base_pcp_handler::AcceptConnectionCallable( - MakePtr(this), client_proxy, endpoint_id, payload_listener)))); + self_, client_proxy, endpoint_id, payload_listener)))); return waitForResult("acceptConnection(" + endpoint_id + ")", client_proxy->getClientId(), result.get()); } @@ -820,7 +823,7 @@ Status::Value BasePCPHandler::rejectConnection( ScopedPtr>> result( runOnPCPHandlerThread( MakePtr(new base_pcp_handler::RejectConnectionCallable( - MakePtr(this), client_proxy, endpoint_id)))); + self_, client_proxy, endpoint_id)))); return waitForResult("rejectConnection(" + endpoint_id + ")", client_proxy->getClientId(), result.get()); } @@ -845,8 +848,7 @@ void BasePCPHandler::processEndpointDisconnection( Ptr process_disconnection_barrier) { runOnPCPHandlerThread(MakePtr( new base_pcp_handler::ProcessEndpointDisconnectionRunnable( - MakePtr(this), client_proxy, endpoint_id, - process_disconnection_barrier))); + self_, client_proxy, endpoint_id, process_disconnection_barrier))); } template @@ -856,7 +858,7 @@ void BasePCPHandler::onEncryptionSuccessImpl( ConstPtr raw_authentication_token) { runOnPCPHandlerThread( MakePtr(new base_pcp_handler::OnEncryptionSuccessRunnable( - MakePtr(this), endpoint_id, ukey2_handshake, authentication_token, + self_, endpoint_id, ukey2_handshake, authentication_token, raw_authentication_token))); } @@ -865,7 +867,7 @@ void BasePCPHandler::onEncryptionFailureImpl( const string& endpoint_id, Ptr channel) { runOnPCPHandlerThread( MakePtr(new base_pcp_handler::OnEncryptionFailureRunnable( - MakePtr(this), endpoint_id, channel))); + self_, endpoint_id, channel))); } template @@ -1025,8 +1027,8 @@ void BasePCPHandler::onConnectionResponse( ScopedPtr> latch(Platform::createCountDownLatch(1)); runOnPCPHandlerThread( MakePtr(new base_pcp_handler::OnConnectionResponseRunnable( - MakePtr(this), client_proxy, endpoint_id, - connection_response_offline_frame, latch.get()))); + self_, client_proxy, endpoint_id, connection_response_offline_frame, + latch.get()))); waitForLatch("onConnectionResponse()", latch.get()); } @@ -1154,8 +1156,8 @@ Exception::Value BasePCPHandler::onIncomingConnection( // Next, we'll set up encryption. encryption_runner_->startServer( client_proxy, connection_request.endpoint_id(), endpoint_channel, - MakePtr(new typename BasePCPHandler::ResultListenerFacade( - MakePtr(this)))); + MakePtr(new + typename BasePCPHandler::ResultListenerFacade(self_))); return Exception::NONE; } diff --git a/cpp/core/internal/base_pcp_handler.h b/cpp/core/internal/base_pcp_handler.h index 0d243165..9019a9b9 100644 --- a/cpp/core/internal/base_pcp_handler.h +++ b/cpp/core/internal/base_pcp_handler.h @@ -496,6 +496,7 @@ class BasePCPHandler // 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*){}}; }; } // namespace connections diff --git a/cpp/core/internal/ble_advertisement_test.cc b/cpp/core/internal/ble_advertisement_test.cc index 953e5262..683aa6b3 100644 --- a/cpp/core/internal/ble_advertisement_test.cc +++ b/cpp/core/internal/ble_advertisement_test.cc @@ -290,9 +290,14 @@ TEST(BLEAdvertisementTest, DeserializationPassesWithLongLength) { endpoint_name, bluetooth_mac_address)); // 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 ByteArray(scoped_ble_advertisement_bytes.get()->getData(), - BLEAdvertisement::kMinAdvertisementLength + 1000))); + new_array)); // Deserialize the long BLE advertisement. ScopedPtr > scoped_long_ble_advertisement( @@ -327,9 +332,14 @@ TEST(BLEAdvertisementTest, DeserializationWorksWithLongEndpointName) { 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 ByteArray(scoped_corrupt_ble_advertisement_bytes.get()->getData(), - BLEAdvertisement::kMinAdvertisementLength + 1000))); + new_array)); // And deserialize the changed BLE Advertisement. ScopedPtr > scoped_ble_advertisement( diff --git a/cpp/core/internal/endpoint_channel_manager.cc b/cpp/core/internal/endpoint_channel_manager.cc index 745c41b1..80222b6a 100644 --- a/cpp/core/internal/endpoint_channel_manager.cc +++ b/cpp/core/internal/endpoint_channel_manager.cc @@ -201,10 +201,7 @@ EndpointChannelManager::ChannelState::updateChannelForEndpoint( ScopedPtr > scoped_previous_endpoint_channel( previous_endpoint_channel); - // Upgrade endpoint_channel to be reference-counted before starting to track - // it (and make it clear that endpoint_channel no longer owns the raw - // pointer). - endpoint_metadata->endpoint_channel = MakeRefCountedPtr(&(*endpoint_channel)); + endpoint_metadata->endpoint_channel = endpoint_channel; endpoint_channel.clear(); endpoint_id_to_metadata_[endpoint_id] = endpoint_metadata; diff --git a/cpp/core/internal/endpoint_manager.cc b/cpp/core/internal/endpoint_manager.cc index ce63e36a..d4d6c3de 100644 --- a/cpp/core/internal/endpoint_manager.cc +++ b/cpp/core/internal/endpoint_manager.cc @@ -497,7 +497,7 @@ void EndpointManager::registerIncomingOfflineFrameProcessor( processor) { runOnEndpointManagerThread(MakePtr( new endpoint_manager::RegisterIncomingOfflineFrameProcessorRunnable< - Platform>(MakePtr(this), frame_type, processor))); + Platform>(self_, frame_type, processor))); } template @@ -507,7 +507,7 @@ void EndpointManager::unregisterIncomingOfflineFrameProcessor( processor) { runOnEndpointManagerThread(MakePtr( new endpoint_manager::UnregisterIncomingOfflineFrameProcessorRunnable< - Platform>(MakePtr(this), frame_type, processor))); + Platform>(self_, frame_type, processor))); } template @@ -521,7 +521,7 @@ EndpointManager::getOfflineFrameProcessor( ScopedPtr future_result( runOnEndpointManagerThread(MakePtr( new endpoint_manager::GetOfflineFrameProcessorCallable( - MakePtr(this), frame_type)))); + self_, frame_type)))); return waitForResult("getOfflineFrameProcessor", future_result.get()); } @@ -536,7 +536,7 @@ void EndpointManager::registerEndpoint( ScopedPtr> latch(Platform::createCountDownLatch(1)); runOnEndpointManagerThread( MakePtr(new endpoint_manager::RegisterEndpointRunnable( - MakePtr(this), client_proxy, endpoint_id, endpoint_name, + 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()); @@ -548,7 +548,7 @@ void EndpointManager::unregisterEndpoint( ScopedPtr> latch(Platform::createCountDownLatch(1)); runOnEndpointManagerThread( MakePtr(new endpoint_manager::UnregisterEndpointRunnable( - MakePtr(this), client_proxy, endpoint_id, latch.get()))); + self_, client_proxy, endpoint_id, latch.get()))); waitForLatch("unregisterEndpoint", latch.get()); } @@ -557,7 +557,7 @@ void EndpointManager::discardEndpoint( Ptr> client_proxy, const string& endpoint_id) { runOnEndpointManagerThread( MakePtr(new endpoint_manager::DiscardEndpointRunnable( - MakePtr(this), client_proxy, endpoint_id))); + self_, client_proxy, endpoint_id))); } template diff --git a/cpp/core/internal/endpoint_manager.h b/cpp/core/internal/endpoint_manager.h index ae176b1d..05263f2c 100644 --- a/cpp/core/internal/endpoint_manager.h +++ b/cpp/core/internal/endpoint_manager.h @@ -2,6 +2,7 @@ #define CORE_INTERNAL_ENDPOINT_MANAGER_H_ #include +#include #include "core/internal/client_proxy.h" #include "core/internal/endpoint_channel.h" @@ -221,6 +222,7 @@ class EndpointManager { ScopedPtr > endpoint_readers_thread_pool_; ScopedPtr > serial_executor_; + std::shared_ptr> self_{this, [](void*){}}; }; } // namespace connections diff --git a/cpp/core/internal/mediums/advertisement_read_result_test.cc b/cpp/core/internal/mediums/advertisement_read_result_test.cc index dd3e7c8b..158e01fb 100644 --- a/cpp/core/internal/mediums/advertisement_read_result_test.cc +++ b/cpp/core/internal/mediums/advertisement_read_result_test.cc @@ -10,8 +10,6 @@ namespace nearby { namespace connections { namespace mediums { -namespace { - class SampleSystemClock : public SystemClock { public: SampleSystemClock() {} @@ -30,13 +28,24 @@ class SamplePlatform { } }; -// We keep a copy of these constants because this is an old-school test (so we -// can't delare it as a friend class of AdvertisementReadResult). +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 -const char kAdvertisementBytes[] = {0x0A, 0x0B, 0x0C}; + +template <> +const std::int64_t AdvertisementReadResult< + SamplePlatform>::kAdvertisementMaxBackoffDurationMillis = + ToInt64Milliseconds(kAdvertisementMaxBackoffDuration); +template <> +const std::int64_t + AdvertisementReadResult< + SamplePlatform>::kAdvertisementBaseBackoffDurationMillis = + ToInt64Milliseconds(kAdvertisementBaseBackoffDuration); TEST(AdvertisementReadResultTest, AdvertisementExists) { AdvertisementReadResult advertisement_read_result; @@ -141,7 +150,6 @@ TEST(AdvertisementReadResultTest, GetDurationSinceRead) { ASSERT_GE(advertisement_read_result.getDurationSinceReadMillis(), sleepTime); } -} // namespace } // namespace mediums } // namespace connections } // namespace nearby diff --git a/cpp/core/internal/mediums/ble_advertisement_test.cc b/cpp/core/internal/mediums/ble_advertisement_test.cc index 22200fa3..965cd543 100644 --- a/cpp/core/internal/mediums/ble_advertisement_test.cc +++ b/cpp/core/internal/mediums/ble_advertisement_test.cc @@ -1,5 +1,7 @@ #include "core/internal/mediums/ble_advertisement.h" +#include + #include "gtest/gtest.h" namespace location { @@ -224,9 +226,10 @@ TEST(BLEAdvertisementTest, DeserializationWorksWithExtraBytes) { // 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]; + char raw_ble_advertisement_bytes[kLongAdvertisementLength] {}; memcpy(raw_ble_advertisement_bytes, scoped_ble_advertisement_bytes->getData(), - kLongAdvertisementLength); + 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( diff --git a/cpp/core/internal/mediums/ble_packet.h b/cpp/core/internal/mediums/ble_packet.h index 14b218be..ec7cf0c7 100644 --- a/cpp/core/internal/mediums/ble_packet.h +++ b/cpp/core/internal/mediums/ble_packet.h @@ -41,6 +41,38 @@ class BLEPacket { 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 diff --git a/cpp/core/internal/mediums/ble_peripheral.h b/cpp/core/internal/mediums/ble_peripheral.h index c305171f..0c5acd01 100644 --- a/cpp/core/internal/mediums/ble_peripheral.h +++ b/cpp/core/internal/mediums/ble_peripheral.h @@ -22,6 +22,21 @@ class BLEPeripheral { 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 diff --git a/cpp/core/internal/mediums/ble_v2.cc b/cpp/core/internal/mediums/ble_v2.cc index 145a9904..32ba762c 100644 --- a/cpp/core/internal/mediums/ble_v2.cc +++ b/cpp/core/internal/mediums/ble_v2.cc @@ -405,7 +405,7 @@ bool BLEV2::startScanning( fast_advertisement_service_uuid); // Avoid leaks. ScopedPtr> scan_callback_facade( - new ScanCallbackFacade(MakePtr(this))); + new ScanCallbackFacade(self_)); std::set service_uuids; service_uuids.insert(kCopresenceServiceUuid); if (!ble_medium_->startScanning(service_uuids, power_mode, @@ -427,7 +427,7 @@ void BLEV2::onAdvertisementFoundImpl( ConstPtr advertisement_data) { offloadFromPlatformThread( MakePtr(new ble_v2::OnAdvertisementFoundRunnable( - MakePtr(this), ble_peripheral, advertisement_data))); + self_, ble_peripheral, advertisement_data))); } // This method is synchronized because it affects class state, but is called @@ -461,11 +461,6 @@ void BLEV2::stopScanning() { // TODO(b/112199086) Change to RecurringCancelableAlarm template Ptr> BLEV2::createOnLostAlarm() { - // return MakePtr(new CancelableAlarm( - // "BluetoothLowEnergy.startScanning() onLost", - // MakePtr(new - // ble_v2::ProcessOnLostRunnable(MakePtr(this))), - // kOnLostTimeoutMillis, on_lost_executor_.get())); return Ptr>(); } @@ -606,7 +601,7 @@ bool BLEV2::internalStartAdvertisementGattServer( ScopedPtr> connection_lifecycle_callback( - new ServerGATTConnectionLifecycleCallbackFacade(MakePtr(this))); + new ServerGATTConnectionLifecycleCallbackFacade(self_)); ScopedPtr> gatt_server( ble_medium_->startGATTServer(connection_lifecycle_callback.get())); if (gatt_server.isNull()) { @@ -737,7 +732,7 @@ BLEV2::internalReadFromAdvertisementGattServer( ScopedPtr> connection_lifecycle_callback( - new ClientGATTConnectionLifecycleCallbackFacade(MakePtr(this))); + new ClientGATTConnectionLifecycleCallbackFacade(self_)); ScopedPtr> gatt_connection( ble_medium_->connectToGATTServer(peripheral, kDefaultMtu, BLEMediumV2::PowerMode::HIGH, diff --git a/cpp/core/internal/mediums/ble_v2.h b/cpp/core/internal/mediums/ble_v2.h index fc568d10..d8f07bd2 100644 --- a/cpp/core/internal/mediums/ble_v2.h +++ b/cpp/core/internal/mediums/ble_v2.h @@ -300,6 +300,7 @@ class BLEV2 { Ptr advertising_info_; Ptr gatt_server_info_; Ptr accepting_connections_info_; + std::shared_ptr self_{this, [](void*){}}; }; } // namespace mediums diff --git a/cpp/core/internal/mediums/bloom_filter_test.cc b/cpp/core/internal/mediums/bloom_filter_test.cc index fe3fbfe1..00ad384a 100644 --- a/cpp/core/internal/mediums/bloom_filter_test.cc +++ b/cpp/core/internal/mediums/bloom_filter_test.cc @@ -71,8 +71,7 @@ TEST(BloomFilterTest, AddMultipleArgsReturnsNonemptyArray) { ScopedPtr> scoped_bloom_filter_bytes( scoped_bloom_filter->asBytes()); std::string empty_string(kByteArrayLength, '\0'); - ASSERT_NE(0, memcmp(scoped_bloom_filter_bytes->getData(), empty_string.data(), - empty_string.size())); + ASSERT_NE(scoped_bloom_filter_bytes->asString(), empty_string); } /** diff --git a/cpp/core/internal/offline_frames.cc b/cpp/core/internal/offline_frames.cc index 8004286a..232a6c89 100644 --- a/cpp/core/internal/offline_frames.cc +++ b/cpp/core/internal/offline_frames.cc @@ -1,85 +1,71 @@ #include "core/internal/offline_frames.h" -#include "platform/port/down_cast.h" +#include +#include + +#include "platform/byte_array.h" namespace location { namespace nearby { namespace connections { +using ExceptionOrOfflineFrame = ExceptionOr>; + namespace { - -template -T *downcastToRaw(Ptr message) { - return DOWN_CAST(message.operator->()); -} - -// This method takes ownership of the passed-in 'message'. -// -// This can be implemented more efficiently by taking in a reference to an -// OfflineFrame object created on the caller's stack, but we instead create it -// on the heap and return a Ptr to it for the sake of consistency. -ConstPtr newOfflineFrame(V1Frame::FrameType frame_type, - Ptr message) { +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( - downcastToRaw(message)); + static_cast(message.release())); break; case V1Frame::CONNECTION_RESPONSE: v1_frame->set_allocated_connection_response( - downcastToRaw(message)); + static_cast(message.release())); break; case V1Frame::PAYLOAD_TRANSFER: v1_frame->set_allocated_payload_transfer( - downcastToRaw(message)); + static_cast(message.release())); break; case V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION: v1_frame->set_allocated_bandwidth_upgrade_negotiation( - downcastToRaw(message)); + static_cast(message.release())); break; case V1Frame::KEEP_ALIVE: v1_frame->set_allocated_keep_alive( - downcastToRaw(message)); + static_cast(message.release())); break; default: break; } - Ptr offline_frame(new OfflineFrame()); + auto offline_frame = std::make_unique(); offline_frame->set_version(OfflineFrame::V1); offline_frame->set_allocated_v1(v1_frame); - return ConstifyPtr(offline_frame); + return offline_frame; } -// This method takes ownership of the passed-in 'offline_frame' and destroys it -// before returning. -ConstPtr toBytes(ConstPtr offline_frame) { - ScopedPtr > scoped_offline_frame(offline_frame); - - size_t serialized_size = offline_frame->ByteSizeLong(); - Ptr bytes{new ByteArray{serialized_size}}; - - offline_frame->SerializeToArray(bytes->getData(), serialized_size); - return ConstifyPtr(bytes); +ConstPtr toBytes(std::unique_ptr offline_frame) { + auto *bytes = new ByteArray{offline_frame->ByteSizeLong()}; + offline_frame->SerializeToArray(bytes->getData(), bytes->size()); + return MakeConstPtr(bytes); } } // namespace -ExceptionOr > OfflineFrames::fromBytes( +ExceptionOrOfflineFrame OfflineFrames::fromBytes( ConstPtr offline_frame_bytes) { - ScopedPtr > offline_frame(new OfflineFrame()); + auto offline_frame = std::make_unique(); - if (!offline_frame->ParseFromArray(offline_frame_bytes->getData(), - offline_frame_bytes->size())) { - return ExceptionOr >( - Exception::INVALID_PROTOCOL_BUFFER); + if (!offline_frame->ParseFromString(offline_frame_bytes->asString())) { + return ExceptionOrOfflineFrame(Exception::INVALID_PROTOCOL_BUFFER); } - return ExceptionOr >( - ConstifyPtr(offline_frame.release())); + return ExceptionOrOfflineFrame(MakeConstPtr(offline_frame.release())); } V1Frame::FrameType OfflineFrames::getFrameType( @@ -96,7 +82,7 @@ ConstPtr OfflineFrames::forConnectionRequest( const std::string &endpoint_id, const std::string &endpoint_name, std::int32_t nonce, const std::vector &mediums) { - Ptr connection_request(new ConnectionRequestFrame()); + auto connection_request = std::make_unique(); connection_request->set_endpoint_id(endpoint_id); connection_request->set_endpoint_name(endpoint_name); connection_request->set_nonce(nonce); @@ -107,113 +93,113 @@ ConstPtr OfflineFrames::forConnectionRequest( connection_request->add_mediums(mediumToConnectionRequestMedium(*it)); } - return toBytes( - newOfflineFrame(V1Frame::CONNECTION_REQUEST, connection_request)); + return toBytes(NewOfflineFrame(V1Frame::CONNECTION_REQUEST, + std::move(connection_request))); } ConstPtr OfflineFrames::forConnectionResponse(std::int32_t status) { - Ptr connection_response( - new ConnectionResponseFrame()); + auto connection_response = std::make_unique(); connection_response->set_status(status); - return toBytes( - newOfflineFrame(V1Frame::CONNECTION_RESPONSE, connection_response)); + return toBytes(NewOfflineFrame(V1Frame::CONNECTION_RESPONSE, + std::move(connection_response))); } ConstPtr OfflineFrames::forDataPayloadTransferFrame( const PayloadTransferFrame::PayloadHeader &header, const PayloadTransferFrame::PayloadChunk &chunk) { - Ptr payload_transfer(new PayloadTransferFrame()); + 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; - return toBytes(newOfflineFrame(V1Frame::PAYLOAD_TRANSFER, payload_transfer)); + return toBytes( + NewOfflineFrame(V1Frame::PAYLOAD_TRANSFER, std::move(payload_transfer))); } ConstPtr OfflineFrames::forControlPayloadTransferFrame( const PayloadTransferFrame::PayloadHeader &header, const PayloadTransferFrame::ControlMessage &control) { - Ptr payload_transfer(new PayloadTransferFrame()); + 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; - return toBytes(newOfflineFrame(V1Frame::PAYLOAD_TRANSFER, payload_transfer)); + return toBytes( + NewOfflineFrame(V1Frame::PAYLOAD_TRANSFER, std::move(payload_transfer))); } ConstPtr OfflineFrames:: forWifiHotspotUpgradePathAvailableBandwidthUpgradeNegotiationEvent( const std::string &ssid, const std::string &password, std::int32_t port) { - BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WifiHotspotCredentials - *wifi_hotspot_credentials = new BandwidthUpgradeNegotiationFrame:: - UpgradePathInfo::WifiHotspotCredentials(); + auto *wifi_hotspot_credentials = new BandwidthUpgradeNegotiationFrame:: + UpgradePathInfo::WifiHotspotCredentials(); wifi_hotspot_credentials->set_ssid(ssid); wifi_hotspot_credentials->set_password(password); wifi_hotspot_credentials->set_port(port); - BandwidthUpgradeNegotiationFrame::UpgradePathInfo *upgrade_path_info = + 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); - Ptr bandwidth_upgrade_negotiation( - new BandwidthUpgradeNegotiationFrame()); + 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, - bandwidth_upgrade_negotiation)); + return toBytes(NewOfflineFrame(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION, + std::move(bandwidth_upgrade_negotiation))); } ConstPtr OfflineFrames::forLastWriteToPriorChannelBandwidthUpgradeNegotiationEvent() { - Ptr bandwidth_upgrade_negotiation( - new BandwidthUpgradeNegotiationFrame()); + auto bandwidth_upgrade_negotiation = + std::make_unique(); bandwidth_upgrade_negotiation->set_event_type( BandwidthUpgradeNegotiationFrame::LAST_WRITE_TO_PRIOR_CHANNEL); - return toBytes(newOfflineFrame(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION, - bandwidth_upgrade_negotiation)); + return toBytes(NewOfflineFrame(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION, + std::move(bandwidth_upgrade_negotiation))); } ConstPtr OfflineFrames::forSafeToClosePriorChannelBandwidthUpgradeNegotiationEvent() { - Ptr bandwidth_upgrade_negotiation( - new BandwidthUpgradeNegotiationFrame()); + auto bandwidth_upgrade_negotiation = + std::make_unique(); bandwidth_upgrade_negotiation->set_event_type( BandwidthUpgradeNegotiationFrame::SAFE_TO_CLOSE_PRIOR_CHANNEL); - return toBytes(newOfflineFrame(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION, - bandwidth_upgrade_negotiation)); + return toBytes(NewOfflineFrame(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION, + std::move(bandwidth_upgrade_negotiation))); } ConstPtr OfflineFrames::forClientIntroductionBandwidthUpgradeNegotiationEvent( const std::string &endpoint_id) { - BandwidthUpgradeNegotiationFrame::ClientIntroduction *client_introduction = + auto *client_introduction = new BandwidthUpgradeNegotiationFrame::ClientIntroduction(); client_introduction->set_endpoint_id(endpoint_id); - Ptr bandwidth_upgrade_negotiation( - new BandwidthUpgradeNegotiationFrame()); + 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, - bandwidth_upgrade_negotiation)); + return toBytes(NewOfflineFrame(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION, + std::move(bandwidth_upgrade_negotiation))); } ConstPtr OfflineFrames::forKeepAlive() { - Ptr keep_alive_frame(new KeepAliveFrame()); - return toBytes(newOfflineFrame(V1Frame::KEEP_ALIVE, keep_alive_frame)); + return toBytes( + NewOfflineFrame(V1Frame::KEEP_ALIVE, std::make_unique())); } ConnectionRequestFrame::Medium OfflineFrames::mediumToConnectionRequestMedium( diff --git a/cpp/core/internal/offline_frames_test.cc b/cpp/core/internal/offline_frames_test.cc new file mode 100644 index 00000000..874b3a74 --- /dev/null +++ b/cpp/core/internal/offline_frames_test.cc @@ -0,0 +1,88 @@ +#include "core/internal/offline_frames.h" + +#include + +#include "proto/connections/offline_wire_formats.pb.h" +#include "platform/byte_array.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace location::nearby::connections { + +namespace { +using Medium = proto::connections::Medium; + +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; +} + +void SetSubframe(V1Frame* frame, ConnectionRequestFrame* sub_frame) { + frame->set_type(V1Frame::CONNECTION_REQUEST); + frame->set_allocated_connection_request(sub_frame); +} + +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; + } +} + +} // namespace + +TEST(OfflineFramesTest, CanParseMessageFromBytes) { + const string endpoint_id{"ABC"}; + const 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 diff --git a/cpp/core/internal/p2p_cluster_pcp_handler.cc b/cpp/core/internal/p2p_cluster_pcp_handler.cc index 36443bd0..84881eef 100644 --- a/cpp/core/internal/p2p_cluster_pcp_handler.cc +++ b/cpp/core/internal/p2p_cluster_pcp_handler.cc @@ -134,14 +134,14 @@ P2PClusterPCPHandler::startDiscoveryImpl( proto::connections::Medium bluetooth_medium = startBluetoothDiscovery(MakePtr(new FoundBluetoothAdvertisementProcessor( - MakePtr(this), client_proxy, service_id)), + self_, client_proxy, service_id)), client_proxy, service_id); if (proto::connections::UNKNOWN_MEDIUM != bluetooth_medium) { mediums_started_successfully.push_back(bluetooth_medium); } proto::connections::Medium ble_medium = startBleDiscovery( - MakePtr(new FoundBleAdvertisementProcessor(MakePtr(this), client_proxy)), + MakePtr(new FoundBleAdvertisementProcessor(self_, client_proxy)), client_proxy, service_id); if (proto::connections::UNKNOWN_MEDIUM != ble_medium) { mediums_started_successfully.push_back(ble_medium); @@ -312,7 +312,7 @@ void P2PClusterPCPHandler::FoundBluetoothAdvertisementProcessor:: onFoundBluetoothDevice(Ptr bluetooth_device) { pcp_handler_->runOnPCPHandlerThread( MakePtr(new OnFoundBluetoothDeviceRunnable(pcp_handler_, client_proxy_, - MakePtr(this), service_id_, + self_, service_id_, bluetooth_device))); } @@ -320,7 +320,7 @@ template void P2PClusterPCPHandler::FoundBluetoothAdvertisementProcessor:: onLostBluetoothDevice(Ptr bluetooth_device) { pcp_handler_->runOnPCPHandlerThread(MakePtr(new OnLostBluetoothDeviceRunnable( - pcp_handler_, client_proxy_, MakePtr(this), service_id_, + pcp_handler_, client_proxy_, self_, service_id_, bluetooth_device))); } @@ -450,7 +450,7 @@ void P2PClusterPCPHandler::FoundBleAdvertisementProcessor:: const string& service_id, ConstPtr advertisement_bytes) { pcp_handler_->runOnPCPHandlerThread(MakePtr(new OnFoundBlePeripheralRunnable( - pcp_handler_, client_proxy_, MakePtr(this), service_id, ble_peripheral, + pcp_handler_, client_proxy_, self_, service_id, ble_peripheral, advertisement_bytes))); } @@ -532,7 +532,7 @@ void P2PClusterPCPHandler::FoundBleAdvertisementProcessor:: onLostBlePeripheral(Ptr ble_peripheral, const string& service_id) { pcp_handler_->runOnPCPHandlerThread(MakePtr(new OnLostBlePeripheralRunnable( - pcp_handler_, client_proxy_, MakePtr(this), service_id, ble_peripheral))); + pcp_handler_, client_proxy_, self_, service_id, ble_peripheral))); } template @@ -597,7 +597,7 @@ P2PClusterPCPHandler::startBluetoothAdvertising( if (!medium_manager_->startListeningForIncomingBluetoothConnections( service_id, MakePtr(new IncomingBluetoothConnectionProcessor( - MakePtr(this), client_proxy, local_endpoint_name)))) { + self_, client_proxy, local_endpoint_name)))) { // TODO(tracyzhou): Add logging. return proto::connections::UNKNOWN_MEDIUM; } @@ -654,7 +654,7 @@ proto::connections::Medium P2PClusterPCPHandler::startBleAdvertising( if (!medium_manager_->startListeningForIncomingBleConnections( service_id, MakePtr(new IncomingBleConnectionProcessor( - MakePtr(this), client_proxy, local_endpoint_name)))) { + 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); diff --git a/cpp/core/internal/p2p_cluster_pcp_handler.h b/cpp/core/internal/p2p_cluster_pcp_handler.h index 06e09a7e..78d5c757 100644 --- a/cpp/core/internal/p2p_cluster_pcp_handler.h +++ b/cpp/core/internal/p2p_cluster_pcp_handler.h @@ -208,6 +208,8 @@ class P2PClusterPCPHandler : public BasePCPHandler { Ptr > client_proxy_; const string service_id_; ScopedPtr > expected_service_id_hash_; + std::shared_ptr self_{this, + [](void*) {}}; }; class FoundBleAdvertisementProcessor @@ -281,6 +283,7 @@ class P2PClusterPCPHandler : public BasePCPHandler { // Maps a BLEPeripheral to its corresponding BLEEndpointState. typedef std::map FoundBLEEndpointsMap; FoundBLEEndpointsMap found_ble_endpoints_; + std::shared_ptr self_{this, [](void*) {}}; }; class BluetoothEndpoint @@ -367,6 +370,7 @@ class P2PClusterPCPHandler : public BasePCPHandler { Ptr > client_proxy, Ptr ble_endpoint); Ptr > medium_manager_; + std::shared_ptr self_{this, [](void*) {}}; }; } // namespace connections diff --git a/cpp/core/internal/payload_manager.cc b/cpp/core/internal/payload_manager.cc index ada9ed74..fd749499 100644 --- a/cpp/core/internal/payload_manager.cc +++ b/cpp/core/internal/payload_manager.cc @@ -581,7 +581,9 @@ PayloadManager::PayloadManager( payload_status_update_executor_(Platform::createSingleThreadExecutor()), endpoint_manager_(endpoint_manager) { endpoint_manager_->registerIncomingOfflineFrameProcessor( - V1Frame::PAYLOAD_TRANSFER, MakePtr(this)); + V1Frame::PAYLOAD_TRANSFER, std::static_pointer_cast< + typename EndpointManager::IncomingOfflineFrameProcessor>( + self_)); } template @@ -591,7 +593,9 @@ PayloadManager::~PayloadManager() { // Unregister ourselves from the IncomingOfflineFrameProcessors. endpoint_manager_->unregisterIncomingOfflineFrameProcessor( - V1Frame::CONNECTION_RESPONSE, MakePtr(this)); + 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(); @@ -640,7 +644,7 @@ void PayloadManager::sendPayload( enqueueOutgoingPayload( send_payload_executor, MakePtr(new payload_manager::SendPayloadRunnable( - MakePtr(this), client_proxy, endpoint_ids, + self_, client_proxy, endpoint_ids, scoped_payload.release()))); // TODO(tracyzhou): Add logging. } @@ -694,7 +698,7 @@ void PayloadManager::processEndpointDisconnection( Ptr process_disconnection_barrier) { payload_status_update_executor_->execute(MakePtr( new payload_manager::ProcessEndpointDisconnectionRunnable( - MakePtr(this), client_proxy, endpoint_id, + self_, client_proxy, endpoint_id, process_disconnection_barrier))); } @@ -830,7 +834,7 @@ void PayloadManager::sendClientCallbacksForFinishedOutgoingPayload( payload_status_update_executor_->execute(MakePtr( new payload_manager:: SendClientCallbacksForFinishedOutgoingPayloadRunnable( - MakePtr(this), client_proxy, finished_endpoint_ids, + self_, client_proxy, finished_endpoint_ids, payload_header, num_bytes_successfully_transferred, status))); } @@ -842,7 +846,7 @@ void PayloadManager::sendClientCallbacksForFinishedIncomingPayload( payload_status_update_executor_->execute(MakePtr( new payload_manager:: SendClientCallbacksForFinishedIncomingPayloadRunnable( - MakePtr(this), client_proxy, endpoint_id, payload_header, + self_, client_proxy, endpoint_id, payload_header, offset_bytes, status))); } @@ -935,7 +939,7 @@ void PayloadManager::handleSuccessfulOutgoingChunk( std::int64_t payload_chunk_body_size) { payload_status_update_executor_->execute(MakePtr( new payload_manager::HandleSuccessfulOutgoingChunkRunnable( - MakePtr(this), client_proxy, endpoint_id, payload_header, + self_, client_proxy, endpoint_id, payload_header, payload_chunk_flags, payload_chunk_offset, payload_chunk_body_size))); } @@ -947,7 +951,7 @@ void PayloadManager::handleSuccessfulIncomingChunk( std::int64_t payload_chunk_body_size) { payload_status_update_executor_->execute(MakePtr( new payload_manager::HandleSuccessfulIncomingChunkRunnable( - MakePtr(this), client_proxy, endpoint_id, payload_header, + self_, client_proxy, endpoint_id, payload_header, payload_chunk_flags, payload_chunk_offset, payload_chunk_body_size))); } diff --git a/cpp/core/internal/payload_manager.h b/cpp/core/internal/payload_manager.h index 27949155..4058ec6f 100644 --- a/cpp/core/internal/payload_manager.h +++ b/cpp/core/internal/payload_manager.h @@ -277,6 +277,7 @@ class PayloadManager payload_status_update_executor_; Ptr > endpoint_manager_; + std::shared_ptr self_{this, [](void*){}}; }; } // namespace connections diff --git a/cpp/core/internal/service_controller_router.cc b/cpp/core/internal/service_controller_router.cc index 41428368..aa76330e 100644 --- a/cpp/core/internal/service_controller_router.cc +++ b/cpp/core/internal/service_controller_router.cc @@ -497,7 +497,7 @@ void ServiceControllerRouter::startAdvertising( ConstPtr start_advertising_params) { routeToServiceController( MakePtr(new service_controller_router::StartAdvertisingRunnable( - MakePtr(this), client_proxy, start_advertising_params))); + self_, client_proxy, start_advertising_params))); } template @@ -506,7 +506,7 @@ void ServiceControllerRouter::stopAdvertising( ConstPtr stop_advertising_params) { routeToServiceController( MakePtr(new service_controller_router::StopAdvertisingRunnable( - MakePtr(this), client_proxy, stop_advertising_params))); + self_, client_proxy, stop_advertising_params))); } template @@ -515,7 +515,7 @@ void ServiceControllerRouter::startDiscovery( ConstPtr start_discovery_params) { routeToServiceController( MakePtr(new service_controller_router::StartDiscoveryRunnable( - MakePtr(this), client_proxy, start_discovery_params))); + self_, client_proxy, start_discovery_params))); } template @@ -524,7 +524,7 @@ void ServiceControllerRouter::stopDiscovery( ConstPtr stop_discovery_params) { routeToServiceController( MakePtr(new service_controller_router::StopDiscoveryRunnable( - MakePtr(this), client_proxy, stop_discovery_params))); + self_, client_proxy, stop_discovery_params))); } template @@ -533,7 +533,7 @@ void ServiceControllerRouter::requestConnection( ConstPtr request_connection_params) { routeToServiceController(MakePtr( new service_controller_router::SendConnectionRequestRunnable( - MakePtr(this), client_proxy, request_connection_params))); + self_, client_proxy, request_connection_params))); } template @@ -542,7 +542,7 @@ void ServiceControllerRouter::acceptConnection( ConstPtr accept_connection_params) { routeToServiceController(MakePtr( new service_controller_router::AcceptConnectionRequestRunnable( - MakePtr(this), client_proxy, accept_connection_params))); + self_, client_proxy, accept_connection_params))); } template @@ -551,7 +551,7 @@ void ServiceControllerRouter::rejectConnection( ConstPtr reject_connection_params) { routeToServiceController(MakePtr( new service_controller_router::RejectConnectionRequestRunnable( - MakePtr(this), client_proxy, reject_connection_params))); + self_, client_proxy, reject_connection_params))); } template @@ -561,7 +561,7 @@ void ServiceControllerRouter::initiateBandwidthUpgrade( initiate_bandwidth_upgrade_params) { routeToServiceController(MakePtr( new service_controller_router::InitiateBandwidthUpgradeRunnable( - MakePtr(this), client_proxy, initiate_bandwidth_upgrade_params))); + self_, client_proxy, initiate_bandwidth_upgrade_params))); } template @@ -570,7 +570,7 @@ void ServiceControllerRouter::sendPayload( ConstPtr send_payload_params) { routeToServiceController( MakePtr(new service_controller_router::SendPayloadRunnable( - MakePtr(this), client_proxy, send_payload_params))); + self_, client_proxy, send_payload_params))); } template @@ -579,7 +579,7 @@ void ServiceControllerRouter::cancelPayload( ConstPtr cancel_payload_params) { routeToServiceController( MakePtr(new service_controller_router::CancelPayloadRunnable( - MakePtr(this), client_proxy, cancel_payload_params))); + self_, client_proxy, cancel_payload_params))); } template @@ -588,7 +588,7 @@ void ServiceControllerRouter::disconnectFromEndpoint( ConstPtr disconnect_from_endpoint_params) { routeToServiceController(MakePtr( new service_controller_router::DisconnectFromEndpointRunnable( - MakePtr(this), client_proxy, disconnect_from_endpoint_params))); + self_, client_proxy, disconnect_from_endpoint_params))); } template @@ -597,7 +597,7 @@ void ServiceControllerRouter::stopAllEndpoints( ConstPtr stop_all_endpoint_params) { routeToServiceController( MakePtr(new service_controller_router::StopAllEndpointsRunnable( - MakePtr(this), client_proxy, stop_all_endpoint_params))); + self_, client_proxy, stop_all_endpoint_params))); } template @@ -605,7 +605,7 @@ void ServiceControllerRouter::clientDisconnecting( Ptr> client_proxy) { routeToServiceController(MakePtr( new service_controller_router::ClientDisconnectingRunnable( - MakePtr(this), client_proxy))); + self_, client_proxy))); } template diff --git a/cpp/core/internal/service_controller_router.h b/cpp/core/internal/service_controller_router.h index cf8e7d88..73e2784c 100644 --- a/cpp/core/internal/service_controller_router.h +++ b/cpp/core/internal/service_controller_router.h @@ -140,6 +140,7 @@ class ServiceControllerRouter { Ptr > current_service_controller_; Ptr current_strategy_; ScopedPtr > serializer_; + std::shared_ptr> self_{this, [](void*){}}; }; } // namespace connections diff --git a/cpp/core/internal/wifi_lan_service_info.cc b/cpp/core/internal/wifi_lan_service_info.cc new file mode 100644 index 00000000..7cfb9b3e --- /dev/null +++ b/cpp/core/internal/wifi_lan_service_info.cc @@ -0,0 +1,202 @@ +#include "core/internal/wifi_lan_service_info.h" + +#include + +#include "platform/base64_utils.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(); + } + + 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)); + } + 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 V1 PCP %d", pcp); + return Ptr(); + } +} + +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(); + + // The upper 3 bits are the Version. + char 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++; + + 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; + + // 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(); + } + + return wifi_lan_service_info_name_bytes; +} + +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) {} + +} // namespace connections +} // namespace nearby +} // namespace location diff --git a/cpp/core/internal/wifi_lan_service_info.h b/cpp/core/internal/wifi_lan_service_info.h new file mode 100644 index 00000000..f1114e5f --- /dev/null +++ b/cpp/core/internal/wifi_lan_service_info.h @@ -0,0 +1,96 @@ +#ifndef CORE_INTERNAL_WIFI_LAN_SERVICE_INFO_H_ +#define CORE_INTERNAL_WIFI_LAN_SERVICE_INFO_H_ + +#include + +#include "core/internal/pcp.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 { +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 { + 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); + + static constexpr std::uint32_t kServiceIdHashLength = 3; + + ~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_; } + + 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 uint16 kVersionBitmask = 0x0E0; + static constexpr uint16 kPcpBitmask = 0x01F; + static constexpr uint16 kVersionShift = 5; + + 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_; +}; + +} // namespace connections +} // namespace nearby +} // namespace location + +#endif // CORE_INTERNAL_WIFI_LAN_SERVICE_INFO_H_ diff --git a/cpp/core/internal/wifi_lan_service_info_test.cc b/cpp/core/internal/wifi_lan_service_info_test.cc new file mode 100644 index 00000000..7b7c5ced --- /dev/null +++ b/cpp/core/internal/wifi_lan_service_info_test.cc @@ -0,0 +1,151 @@ +#include "core/internal/wifi_lan_service_info.h" + +#include + +#include "platform/base64_utils.h" +#include "platform/port/string.h" +#include "gtest/gtest.h" + +namespace location { +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. + +TEST(WifiLanServiceInfoTest, SerializationDeserializationWorks) { + ScopedPtr > scoped_service_id_hash(new ByteArray( + kServiceIDHashBytes, sizeof(kServiceIDHashBytes) / sizeof(char))); + + 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())); +} + +TEST(WifiLanServiceInfoTest, + SerializationDeserializationWorksWithEmptyEndpointName) { + ScopedPtr > scoped_service_id_hash(new ByteArray( + kServiceIDHashBytes, sizeof(kServiceIDHashBytes) / sizeof(char))); + + 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())); +} + +TEST(WifiLanServiceInfoTest, SerializationFailsWithBadVersion) { + WifiLanServiceInfo::Version bad_version = + static_cast(666); + + ScopedPtr > scoped_service_id_hash(new ByteArray( + kServiceIDHashBytes, sizeof(kServiceIDHashBytes) / sizeof(char))); + + 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()); +} + +TEST(WifiLanServiceInfoTest, SerializationFailsWithBadPCP) { + PCP::Value bad_pcp = static_cast(666); + + ScopedPtr > scoped_service_id_hash(new ByteArray( + kServiceIDHashBytes, sizeof(kServiceIDHashBytes) / sizeof(char))); + + 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()); +} + +TEST(WifiLanServiceInfoTest, SerializationFailsWithShortEndpointId) { + std::string short_endpoint_id("AB1"); + + ScopedPtr > scoped_service_id_hash(new ByteArray( + kServiceIDHashBytes, sizeof(kServiceIDHashBytes) / sizeof(char))); + + 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()); +} + +TEST(WifiLanServiceInfoTest, SerializationFailsWithLongEndpointId) { + std::string long_endpoint_id("AB12X"); + + ScopedPtr > scoped_service_id_hash(new ByteArray( + kServiceIDHashBytes, sizeof(kServiceIDHashBytes) / sizeof(char))); + + 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()); +} + +TEST(WifiLanServiceInfoTest, SerializationFailsWithShortServiceIdHash) { + char short_service_id_hash_bytes[] = {0x0A, 0x0B}; + + ScopedPtr > scoped_short_service_id_hash( + new ByteArray(short_service_id_hash_bytes, + sizeof(short_service_id_hash_bytes) / sizeof(char))); + + 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()); +} + +TEST(WifiLanServiceInfoTest, SerializationFailsWithLongServiceIdHash) { + char long_service_id_hash_bytes[] = {0x0A, 0x0B, 0x0C, 0x0D}; + + ScopedPtr > scoped_long_service_id_hash( + new ByteArray(long_service_id_hash_bytes, + sizeof(long_service_id_hash_bytes) / sizeof(char))); + + 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()); +} + +TEST(WifiLanServiceInfoTest, DeserializationFailsWithShortLength) { + char wifi_lan_service_info_bytes[] = {'X'}; + + ScopedPtr > scoped_wifi_lan_service_info_bytes( + new ByteArray(wifi_lan_service_info_bytes, + sizeof(wifi_lan_service_info_bytes) / sizeof(char))); + + ScopedPtr > scoped_wifi_lan_service_info( + WifiLanServiceInfo::FromString(Base64Utils::encode( + ConstifyPtr(scoped_wifi_lan_service_info_bytes.get())))); + + EXPECT_TRUE(scoped_wifi_lan_service_info.isNull()); +} + +} // namespace +} // namespace connections +} // namespace nearby +} // namespace location diff --git a/cpp/platform/BUILD b/cpp/platform/BUILD index e7482ef0..72d19bc6 100644 --- a/cpp/platform/BUILD +++ b/cpp/platform/BUILD @@ -26,7 +26,6 @@ cc_library( ":types", "//platform/api", "//platform/port:string", - "//strings", "//absl/strings", "//absl/time", ], @@ -34,15 +33,11 @@ cc_library( cc_library( name = "types", - srcs = [ - "ptr.cc", - ], hdrs = [ "byte_array.h", "callable.h", "cancelable.h", "container_of.h", - "exception.cc", "exception.h", "ptr.h", "runnable.h", @@ -113,6 +108,15 @@ cc_test( ], ) +cc_test( + name = "exception_test", + srcs = ["exception_test.cc"], + deps = [ + ":types", + "//testing/base/public:gunit_main", + ], +) + cc_test( name = "pipe_test", timeout = "short", diff --git a/cpp/platform/api/BUILD b/cpp/platform/api/BUILD index 1b474e13..f1c769b7 100644 --- a/cpp/platform/api/BUILD +++ b/cpp/platform/api/BUILD @@ -20,23 +20,28 @@ cc_library( "hash_utils.h", "input_file.h", "input_stream.h", + "listenable_future.h", "lock.h", "multi_thread_executor.h", "output_file.h", "output_stream.h", "scheduled_executor.h", + "server_sync.h", "settable_future.h", "single_thread_executor.h", "socket.h", "submittable_executor.h", "system_clock.h", "thread_utils.h", + "webrtc.h", "wifi.h", + "wifi_lan.h", ], deps = [ "//platform:types", "//platform/port:down_cast", "//platform/port:string", + "//webrtc/files/stable/webrtc/api:libjingle_peerconnection_api", ], ) diff --git a/cpp/platform/api/ble_v2.h b/cpp/platform/api/ble_v2.h index 93607126..06a88288 100644 --- a/cpp/platform/api/ble_v2.h +++ b/cpp/platform/api/ble_v2.h @@ -39,7 +39,7 @@ struct BLEAdvertisementData { 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 @@ -217,7 +217,8 @@ class GATTServer { // 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::string& service_uuid, + const std::string& characteristic_uuid, const std::set& permissions, const std::set& properties) = 0; @@ -384,7 +385,9 @@ class BLEMediumV2 { // HIGH: // - Connection interval = ~100ms - 125ms virtual Ptr connectToGATTServer( - Ptr peripheral, MTU mtu, PowerMode::Value power_mode, + Ptr peripheral, + MTU mtu, + PowerMode::Value power_mode, Ptr connection_lifecycle_callback) = 0; diff --git a/cpp/platform/api/bluetooth_classic.h b/cpp/platform/api/bluetooth_classic.h index 0ba04b11..154c7f0f 100644 --- a/cpp/platform/api/bluetooth_classic.h +++ b/cpp/platform/api/bluetooth_classic.h @@ -60,7 +60,7 @@ class BluetoothServerSocket { // // The returned Ptr will be owned (and destroyed) by the caller. Returns // Exception::IO on error. - virtual ExceptionOr > accept() = 0; + virtual ExceptionOr> accept() = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#close() // @@ -116,8 +116,9 @@ class BluetoothClassicMedium { // // 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; + virtual ExceptionOr> connectToService( + Ptr remote_device, + const std::string& service_uuid) = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#listenUsingInsecureRfcommWithServiceRecord // @@ -129,8 +130,9 @@ class BluetoothClassicMedium { // // 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; + virtual ExceptionOr> listenForService( + const std::string& service_name, + const std::string& service_uuid) = 0; }; } // namespace nearby diff --git a/cpp/platform/api/executor.h b/cpp/platform/api/executor.h index 2c425d15..2755af36 100644 --- a/cpp/platform/api/executor.h +++ b/cpp/platform/api/executor.h @@ -1,6 +1,9 @@ #ifndef PLATFORM_API_EXECUTOR_H_ #define PLATFORM_API_EXECUTOR_H_ +#include "platform/ptr.h" +#include "platform/runnable.h" + namespace location { namespace nearby { @@ -12,6 +15,9 @@ class Executor { // https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html#shutdown-- 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; }; } // namespace nearby diff --git a/cpp/platform/api/future.h b/cpp/platform/api/future.h index 34f0bbed..166a4ed9 100644 --- a/cpp/platform/api/future.h +++ b/cpp/platform/api/future.h @@ -1,6 +1,8 @@ #ifndef PLATFORM_API_FUTURE_H_ #define PLATFORM_API_FUTURE_H_ +#include + #include "platform/exception.h" namespace location { @@ -16,6 +18,11 @@ class Future { virtual ExceptionOr get() = 0; // throws Exception::INTERRUPTED, Exception::EXECUTION + + // throws Exception::INTERRUPTED, Exception::EXECUTION + // throws Exception::TIMEOUT if |timeout_ms| is exceeded while waiting for + // result. + virtual ExceptionOr get(std::int64_t timeout_ms) = 0; }; } // namespace nearby diff --git a/cpp/platform/api/input_file.h b/cpp/platform/api/input_file.h index 28615919..ed2c782a 100644 --- a/cpp/platform/api/input_file.h +++ b/cpp/platform/api/input_file.h @@ -16,7 +16,7 @@ class 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( + 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; diff --git a/cpp/platform/api/input_stream.h b/cpp/platform/api/input_stream.h index 08bc4a50..02eb6502 100644 --- a/cpp/platform/api/input_stream.h +++ b/cpp/platform/api/input_stream.h @@ -18,9 +18,9 @@ class InputStream { virtual ~InputStream() {} // The returned ConstPtr will be owned (and destroyed) by the caller. - virtual ExceptionOr > read() = 0; // throws Exception::IO + virtual ExceptionOr> read() = 0; // throws Exception::IO // The returned ConstPtr will be owned (and destroyed) by the caller. - virtual ExceptionOr > read( + virtual ExceptionOr> read( std::int64_t size) = 0; // throws Exception::IO virtual Exception::Value close() = 0; // throws Exception::IO }; diff --git a/cpp/platform/api/listenable_future.h b/cpp/platform/api/listenable_future.h new file mode 100644 index 00000000..3cd306e7 --- /dev/null +++ b/cpp/platform/api/listenable_future.h @@ -0,0 +1,28 @@ +#ifndef PLATFORM_API_LISTENABLE_FUTURE_H_ +#define PLATFORM_API_LISTENABLE_FUTURE_H_ + +#include "platform/api/executor.h" +#include "platform/api/future.h" +#include "platform/exception.h" +#include "platform/ptr.h" +#include "platform/runnable.h" + +namespace location { +namespace nearby { + +// 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 {} + + // Executor is shared among multiple runnables. It is not owned by any future. + virtual void addListener(Ptr runnable, Executor* executor) = 0; +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API_LISTENABLE_FUTURE_H_ diff --git a/cpp/platform/api/multi_thread_executor.h b/cpp/platform/api/multi_thread_executor.h index 52a261b5..3770fda4 100644 --- a/cpp/platform/api/multi_thread_executor.h +++ b/cpp/platform/api/multi_thread_executor.h @@ -11,8 +11,8 @@ namespace nearby { // // https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool-int- template -class MultiThreadExecutor : - public SubmittableExecutor { +class MultiThreadExecutor + : public SubmittableExecutor { public: ~MultiThreadExecutor() override {} }; diff --git a/cpp/platform/api/server_sync.h b/cpp/platform/api/server_sync.h new file mode 100644 index 00000000..e6b01aa9 --- /dev/null +++ b/cpp/platform/api/server_sync.h @@ -0,0 +1,64 @@ +#ifndef PLATFORM_API_SERVER_SYNC_H_ +#define PLATFORM_API_SERVER_SYNC_H_ + +#include + +#include "platform/byte_array.h" +#include "platform/ptr.h" + +namespace location { +namespace nearby { + +// Abstraction that represents a Nearby endpoint exchanging data through +// ServerSync Medium. +class ServerSyncDevice { + public: + virtual ~ServerSyncDevice() {} + + virtual std::string getName() = 0; + + virtual std::string getGuid() = 0; + + virtual std::string getOwnGuid() = 0; +}; + +// Container of operations that can be performed over the Chrome Sync medium. +class ServerSyncMedium { + public: + virtual ~ServerSyncMedium() {} + + // 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; + + class DiscoveredDeviceCallback { + public: + virtual ~DiscoveredDeviceCallback() {} + + // 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; + // Called when ServerSyncDevice is no longer reachable. + virtual void onDeviceLost(Ptr device, + const std::string& 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; + // 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; +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API_SERVER_SYNC_H_ diff --git a/cpp/platform/api/settable_future.h b/cpp/platform/api/settable_future.h index 253a5005..f9a5e35c 100644 --- a/cpp/platform/api/settable_future.h +++ b/cpp/platform/api/settable_future.h @@ -1,7 +1,7 @@ #ifndef PLATFORM_API_SETTABLE_FUTURE_H_ #define PLATFORM_API_SETTABLE_FUTURE_H_ -#include "platform/api/future.h" +#include "platform/api/listenable_future.h" namespace location { namespace nearby { @@ -10,11 +10,13 @@ namespace nearby { // // https://google.github.io/guava/releases/20.0/api/docs/com/google/common/util/concurrent/SettableFuture.html template -class SettableFuture : public Future { +class SettableFuture : public ListenableFuture { public: ~SettableFuture() override {} virtual bool set(T value) = 0; + + virtual bool setException(Exception exception) = 0; }; } // namespace nearby diff --git a/cpp/platform/api/single_thread_executor.h b/cpp/platform/api/single_thread_executor.h index 7e2f9c6d..e3338648 100644 --- a/cpp/platform/api/single_thread_executor.h +++ b/cpp/platform/api/single_thread_executor.h @@ -11,8 +11,8 @@ namespace nearby { // // https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newSingleThreadExecutor-- template -class SingleThreadExecutor : - public SubmittableExecutor { +class SingleThreadExecutor + : public SubmittableExecutor { public: ~SingleThreadExecutor() override {} }; diff --git a/cpp/platform/api/submittable_executor.h b/cpp/platform/api/submittable_executor.h index 4775d8ee..3d7bd625 100644 --- a/cpp/platform/api/submittable_executor.h +++ b/cpp/platform/api/submittable_executor.h @@ -6,7 +6,6 @@ #include "platform/callable.h" #include "platform/port/down_cast.h" #include "platform/ptr.h" -#include "platform/runnable.h" namespace location { namespace nearby { @@ -29,12 +28,9 @@ class SubmittableExecutor : public Executor { ~SubmittableExecutor() override {} template - Ptr > submit(Ptr > callable) { + Ptr> submit(Ptr> callable) { return DOWN_CAST(this)->submit(callable); } - - // https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html#execute-java.lang.Runnable- - virtual void execute(Ptr runnable) = 0; }; } // namespace nearby diff --git a/cpp/platform/api/webrtc.h b/cpp/platform/api/webrtc.h new file mode 100644 index 00000000..35f53e60 --- /dev/null +++ b/cpp/platform/api/webrtc.h @@ -0,0 +1,46 @@ +#ifndef PLATFORM_API_WEBRTC_H_ +#define PLATFORM_API_WEBRTC_H_ + +#include + +#include "platform/byte_array.h" +#include "platform/ptr.h" +#include "webrtc/files/stable/webrtc/api/peer_connection_interface.h" + +namespace location { +namespace nearby { + +class WebRtcSignalingMessenger { + public: + virtual ~WebRtcSignalingMessenger() = default; + + /** Called whenever we receive an inbox message from tachyon. */ + class SignalingMessageListener { + public: + virtual ~SignalingMessageListener() = default; + + 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 string& peer_id, + ConstPtr message) = 0; + virtual bool startReceivingMessages( + Ptr listener) = 0; + virtual void getIceServers(Ptr ice_servers_listener) = 0; +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API_WEBRTC_H_ diff --git a/cpp/platform/api/wifi.h b/cpp/platform/api/wifi.h index 0cb2566a..6631d036 100644 --- a/cpp/platform/api/wifi.h +++ b/cpp/platform/api/wifi.h @@ -58,7 +58,7 @@ class WifiMedium { // 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; + const std::vector>& scan_results) = 0; }; // Does not take ownership of the passed-in scan_result_callback -- destroying @@ -69,7 +69,8 @@ class WifiMedium { // WifiConnectionStatus::CONNECTED on success, or the appropriate failure code // otherwise. virtual WifiConnectionStatus::Value connectToNetwork( - const std::string& ssid, const std::string& password, + const std::string& ssid, + const std::string& password, WifiAuthType::Value auth_type) = 0; // Blocks until it's certain of there being a connection to the internet, or diff --git a/cpp/platform/api/wifi_lan.h b/cpp/platform/api/wifi_lan.h new file mode 100644 index 00000000..1b13b393 --- /dev/null +++ b/cpp/platform/api/wifi_lan.h @@ -0,0 +1,94 @@ +#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" + +namespace location { +namespace nearby { + +// Opaque wrapper over a WifiLan service which contains encoded service name. +class WifiLanService { + public: + virtual ~WifiLanService() = default; + + virtual std::string GetName() = 0; +}; + +class WifiLanSocket { + public: + virtual ~WifiLanSocket() = default; + + // Returns the InputStream of the WifiLanSocket, or a null Ptr + // on error. + // + // The returned Ptr is not owned by the caller, and can be invalidated once + // the WifiLanSocket object is destroyed. + virtual Ptr GetInputStream() = 0; + + // Returns the OutputStream of the WifiLanSocket, or a null + // Ptr on error. + // + // The returned Ptr is not owned by the caller, and can be invalidated once + // the WifiLanSocket object is destroyed. + virtual Ptr GetOutputStream() = 0; + + // Returns Exception::IO on error, Exception::NONE otherwise. + virtual Exception::Value 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; +}; + +// 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 string& wifi_lan_service_info_name) = 0; + virtual void 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; + }; + + virtual bool StartDiscovery( + const std::string& service_id, + Ptr discovered_service_callback) = 0; + virtual void StopDiscovery(const std::string& service_id) = 0; + + class AcceptedConnectionCallback { + public: + virtual ~AcceptedConnectionCallback() = default; + + // 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 string& service_id) = 0; + }; + + virtual bool StartAcceptingConnections( + const std::string& service_id, + Ptr accepted_connection_callback) = 0; + virtual void StopAcceptingConnections(const std::string& service_id) = 0; + + virtual Ptr Connect(Ptr wifi_lan_service, + const std::string& service_id) = 0; +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API_WIFI_LAN_H_ diff --git a/cpp/platform/api2/BUILD b/cpp/platform/api2/BUILD new file mode 100644 index 00000000..5313b366 --- /dev/null +++ b/cpp/platform/api2/BUILD @@ -0,0 +1,65 @@ +package(default_visibility = [ + "//core:__subpackages__", + "//platform:__subpackages__", + "//location/nearby/setup/core:__subpackages__", +]) + +cc_library( + name = "api2", + hdrs = [ + "atomic_boolean.h", + "atomic_reference.h", + "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", + "multi_thread_executor.h", + "mutex.h", + "output_file.h", + "output_stream.h", + "scheduled_executor.h", + "server_sync.h", + "settable_future.h", + "single_thread_executor.h", + "socket.h", + "submittable_executor.h", + "system_clock.h", + "thread_utils.h", + "webrtc.h", + "wifi.h", + ], + deps = [ + "//platform:types", + "//absl/strings", + "//absl/time", + "//webrtc/files/stable/webrtc/api:libjingle_peerconnection_api", + ], +) + +cc_library( + name = "mutex", + hdrs = ["mutex.h"], + visibility = [ + "//platform:__subpackages__", + ], +) + +cc_library( + name = "condition_variable", + hdrs = ["condition_variable.h"], + visibility = [ + "//platform:__subpackages__", + ], + deps = [ + "//platform:types", + "//absl/time", + ], +) diff --git a/cpp/platform/api2/atomic_boolean.h b/cpp/platform/api2/atomic_boolean.h new file mode 100644 index 00000000..b5e729fa --- /dev/null +++ b/cpp/platform/api2/atomic_boolean.h @@ -0,0 +1,21 @@ +#ifndef PLATFORM_API2_ATOMIC_BOOLEAN_H_ +#define PLATFORM_API2_ATOMIC_BOOLEAN_H_ + +namespace location { +namespace nearby { + +// 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 bool Get() = 0; + virtual void Set(bool value) = 0; +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_ATOMIC_BOOLEAN_H_ diff --git a/cpp/platform/api2/atomic_reference.h b/cpp/platform/api2/atomic_reference.h new file mode 100644 index 00000000..8740be0d --- /dev/null +++ b/cpp/platform/api2/atomic_reference.h @@ -0,0 +1,22 @@ +#ifndef PLATFORM_API2_ATOMIC_REFERENCE_H_ +#define PLATFORM_API2_ATOMIC_REFERENCE_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 +template +class AtomicReference { + public: + virtual ~AtomicReference() {} + + virtual T Get() = 0; + virtual void Set(const T& value) = 0; +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_ATOMIC_REFERENCE_H_ diff --git a/cpp/platform/api2/ble.h b/cpp/platform/api2/ble.h new file mode 100644 index 00000000..337f0717 --- /dev/null +++ b/cpp/platform/api2/ble.h @@ -0,0 +1,111 @@ +#ifndef PLATFORM_API2_BLE_H_ +#define PLATFORM_API2_BLE_H_ + +#include "platform/api2/bluetooth_classic.h" +#include "platform/api2/input_stream.h" +#include "platform/api2/output_stream.h" +#include "platform/byte_array.h" +#include "absl/strings/string_view.h" + +namespace location { +namespace nearby { + +// 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() {} + + // The returned Ptr is not owned by the caller, and can be invalidated once + // the corresponding BLEPeripheral object is destroyed. + virtual BluetoothDevice& GetBluetoothDevice() = 0; +}; + +class BleSocket { + public: + virtual ~BleSocket() {} + + // 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; + + // The returned object is not owned by the caller, and can be invalidated once + // the BleSocket object is destroyed. + virtual BlePeripheral& GetRemotePeripheral() = 0; +}; + +// Container of operations that can be performed over the BLE medium. +class BleMedium { + public: + virtual ~BleMedium() {} + + virtual bool StartAdvertising(absl::string_view service_id, + const ByteArray& advertisement) = 0; + virtual void StopAdvertising(absl::string_view service_id) = 0; + + class DiscoveredPeripheralCallback { + public: + virtual ~DiscoveredPeripheralCallback() {} + + // The BlePeripheral* is not owned by callbacks. + // It is passed to give access to its non-const methods. + // It is guaranteed to be valid for the duration of call. + virtual void OnPeripheralDiscovered(BlePeripheral* ble_peripheral, + absl::string_view service_id, + const ByteArray& advertisement) = 0; + virtual void OnPeripheralLost(BlePeripheral* ble_peripheral, + absl::string_view service_id) = 0; + }; + + // Returns true once the BLE scan has been initiated. + virtual bool StartScanning( + absl::string_view service_id, + const DiscoveredPeripheralCallback& discovered_peripheral_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 void StopScanning(absl::string_view service_id) = 0; + + // Callback that is invoked when a new connection is accepted. + class AcceptedConnectionCallback { + public: + virtual ~AcceptedConnectionCallback() {} + + virtual void OnConnectionAccepted(std::unique_ptr socket, + absl::string_view service_id) = 0; + }; + + // Returns true once BLE socket connection requests to service_id can be + // accepted. + virtual bool StartAcceptingConnections( + absl::string_view service_id, + const AcceptedConnectionCallback& accepted_connection_callback) = 0; + virtual void StopAcceptingConnections(const std::string& service_id) = 0; + + // BlePeripheral* is not owned by this call; + // it must remain valid for the duration of a call. + virtual std::unique_ptr Connect(BlePeripheral* ble_peripheral, + absl::string_view service_id) = 0; +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_BLE_H_ diff --git a/cpp/platform/api2/ble_v2.h b/cpp/platform/api2/ble_v2.h new file mode 100644 index 00000000..e0573c55 --- /dev/null +++ b/cpp/platform/api2/ble_v2.h @@ -0,0 +1,390 @@ +#ifndef PLATFORM_API2_BLE_V2_H_ +#define PLATFORM_API2_BLE_V2_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "platform/byte_array.h" +#include "platform/exception.h" +#include "absl/strings/string_view.h" + +namespace location { +namespace nearby { +namespace 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 std::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 std::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 std::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 v2 +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_BLE_V2_H_ diff --git a/cpp/platform/api2/bluetooth_adapter.h b/cpp/platform/api2/bluetooth_adapter.h new file mode 100644 index 00000000..21171a01 --- /dev/null +++ b/cpp/platform/api2/bluetooth_adapter.h @@ -0,0 +1,55 @@ +#ifndef PLATFORM_API2_BLUETOOTH_ADAPTER_H_ +#define PLATFORM_API2_BLUETOOTH_ADAPTER_H_ + +#include +#include + +#include "absl/strings/string_view.h" + +namespace location { +namespace nearby { + +// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html +class BluetoothAdapter { + public: + virtual ~BluetoothAdapter() {} + + // 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() = 0; + + // Scan modes of a BluetoothAdapter, as described at + // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getScanMode(). + enum class ScanMode { + kUnknown, + kConnectableDiscoverable, + }; + + // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getScanMode() + // + // Returns ScanMode::kUnknown on error. + virtual ScanMode GetScanMode() = 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; +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_BLUETOOTH_ADAPTER_H_ diff --git a/cpp/platform/api2/bluetooth_classic.h b/cpp/platform/api2/bluetooth_classic.h new file mode 100644 index 00000000..57de4ddc --- /dev/null +++ b/cpp/platform/api2/bluetooth_classic.h @@ -0,0 +1,124 @@ +#ifndef PLATFORM_API2_BLUETOOTH_CLASSIC_H_ +#define PLATFORM_API2_BLUETOOTH_CLASSIC_H_ + +#include +#include + +#include "platform/api2/input_stream.h" +#include "platform/api2/output_stream.h" +#include "platform/byte_array.h" +#include "platform/exception.h" +#include "absl/strings/string_view.h" + +namespace location { +namespace nearby { + +// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html. +class BluetoothDevice { + public: + virtual ~BluetoothDevice() {} + + // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName() + virtual std::string GetName() = 0; +}; + +// https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html. +class BluetoothSocket { + public: + virtual ~BluetoothSocket() {} + + // Returns the InputStream of the BluetoothSocket. + virtual InputStream& GetInputStream() = 0; + + // Returns the OutputStream of the BluetoothSocket. + virtual OutputStream& GetOutputStream() = 0; + + // https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#close() + // + // Returns Exception::kIo on error, Exception::kSuccess otherwise. + virtual Exception Close() = 0; + + // https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#getRemoteDevice() + virtual BluetoothDevice& GetRemoteDevice() = 0; +}; + +// https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html. +class BluetoothServerSocket { + public: + virtual ~BluetoothServerSocket() {} + + // https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#accept() + // + // returns Exception::kIo on error. + virtual ExceptionOr> 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() {} + + class DiscoveryCallback { + public: + virtual ~DiscoveryCallback() {} + + // BluetoothDevice* is not owned by callbacks. + // Pointer is guaranteed to remain valid for the duration of a call. + virtual void OnDeviceDiscovered(BluetoothDevice* device) = 0; + virtual void OnDeviceNameChanged(BluetoothDevice* device) = 0; + virtual void OnDeviceLost(BluetoothDevice* device) = 0; + }; + + // 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(const 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, wrapped in a ExceptionOr object. + // On error, returns Exception object. + virtual ExceptionOr> ConnectToService( + BluetoothDevice* remote_device, absl::string_view 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 Exception::kIo on error. + virtual ExceptionOr> ListenForService( + absl::string_view service_name, absl::string_view service_uuid) = 0; +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_BLUETOOTH_CLASSIC_H_ diff --git a/cpp/platform/api2/condition_variable.h b/cpp/platform/api2/condition_variable.h new file mode 100644 index 00000000..936a3c36 --- /dev/null +++ b/cpp/platform/api2/condition_variable.h @@ -0,0 +1,26 @@ +#ifndef PLATFORM_API2_CONDITION_VARIABLE_H_ +#define PLATFORM_API2_CONDITION_VARIABLE_H_ + +#include "platform/exception.h" + +namespace location { +namespace nearby { + +// 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() {} + + // 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 Wait() = 0; // throws Exception::kInterrupted +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_CONDITION_VARIABLE_H_ diff --git a/cpp/platform/api2/count_down_latch.h b/cpp/platform/api2/count_down_latch.h new file mode 100644 index 00000000..ae0dfc86 --- /dev/null +++ b/cpp/platform/api2/count_down_latch.h @@ -0,0 +1,29 @@ +#ifndef PLATFORM_API2_COUNT_DOWN_LATCH_H_ +#define PLATFORM_API2_COUNT_DOWN_LATCH_H_ + +#include + +#include "platform/exception.h" +#include "absl/time/time.h" + +namespace location { +namespace nearby { + +// 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() {} + + virtual Exception Await() = 0; // throws Exception::kInterrupted + virtual ExceptionOr Await( + absl::Duration timeout) = 0; // throws Exception::kInterrupted + virtual void CountDown() = 0; +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_COUNT_DOWN_LATCH_H_ diff --git a/cpp/platform/api2/executor.h b/cpp/platform/api2/executor.h new file mode 100644 index 00000000..ee561894 --- /dev/null +++ b/cpp/platform/api2/executor.h @@ -0,0 +1,26 @@ +#ifndef PLATFORM_API2_EXECUTOR_H_ +#define PLATFORM_API2_EXECUTOR_H_ + +#include + +#include "platform/runnable.h" + +namespace location { +namespace nearby { + +// This abstract class is the superclass of all classes representing an +// Executor. +class Executor { + public: + virtual ~Executor() = default; + // https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html#execute-java.lang.Runnable- + virtual void Execute(std::unique_ptr runnable) = 0; + + // https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html#shutdown-- + virtual void Shutdown() = 0; +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_EXECUTOR_H_ diff --git a/cpp/platform/api2/future.h b/cpp/platform/api2/future.h new file mode 100644 index 00000000..7f46c484 --- /dev/null +++ b/cpp/platform/api2/future.h @@ -0,0 +1,30 @@ +#ifndef PLATFORM_API2_FUTURE_H_ +#define PLATFORM_API2_FUTURE_H_ + +#include "platform/exception.h" +#include "absl/time/time.h" + +namespace location { +namespace nearby { + +// 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 nearby +} // namespace location + +#endif // PLATFORM_API2_FUTURE_H_ diff --git a/cpp/platform/api2/hash_utils.h b/cpp/platform/api2/hash_utils.h new file mode 100644 index 00000000..fab68f32 --- /dev/null +++ b/cpp/platform/api2/hash_utils.h @@ -0,0 +1,20 @@ +#ifndef PLATFORM_API2_HASH_UTILS_H_ +#define PLATFORM_API2_HASH_UTILS_H_ + +#include "platform/byte_array.h" +#include "absl/strings/string_view.h" + +namespace location { +namespace nearby { + +// A provider of standard hashing algorithms. +class HashUtils { + public: + static ByteArray Md5(absl::string_view input); + static ByteArray Sha256(absl::string_view input); +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_HASH_UTILS_H_ diff --git a/cpp/platform/api2/input_file.h b/cpp/platform/api2/input_file.h new file mode 100644 index 00000000..0191aff8 --- /dev/null +++ b/cpp/platform/api2/input_file.h @@ -0,0 +1,24 @@ +#ifndef PLATFORM_API2_INPUT_FILE_H_ +#define PLATFORM_API2_INPUT_FILE_H_ + +#include + +#include "platform/api2/input_stream.h" +#include "platform/byte_array.h" +#include "platform/exception.h" + +namespace location { +namespace nearby { + +// An InputFile represents a readable file on the system. +class InputFile : public InputStream { + public: + ~InputFile() override = default; + virtual std::string GetFilePath() const = 0; + virtual size_t GetTotalSize() const = 0; +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_INPUT_FILE_H_ diff --git a/cpp/platform/api2/input_stream.h b/cpp/platform/api2/input_stream.h new file mode 100644 index 00000000..f91a5466 --- /dev/null +++ b/cpp/platform/api2/input_stream.h @@ -0,0 +1,27 @@ +#ifndef PLATFORM_API2_INPUT_STREAM_H_ +#define PLATFORM_API2_INPUT_STREAM_H_ + +#include + +#include "platform/byte_array.h" +#include "platform/exception.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() {} + + virtual ExceptionOr Read( + size_t size) = 0; // throws Exception::kIo + virtual Exception Close() = 0; // throws Exception::kIo +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_INPUT_STREAM_H_ diff --git a/cpp/platform/api2/listenable_future.h b/cpp/platform/api2/listenable_future.h new file mode 100644 index 00000000..2993bc88 --- /dev/null +++ b/cpp/platform/api2/listenable_future.h @@ -0,0 +1,29 @@ +#ifndef PLATFORM_API2_LISTENABLE_FUTURE_H_ +#define PLATFORM_API2_LISTENABLE_FUTURE_H_ + +#include + +#include "platform/api2/executor.h" +#include "platform/api2/future.h" +#include "platform/exception.h" +#include "platform/runnable.h" + +namespace location { +namespace nearby { + +// 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(std::unique_ptr runnable, + Executor* executor) = 0; +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_LISTENABLE_FUTURE_H_ diff --git a/cpp/platform/api2/multi_thread_executor.h b/cpp/platform/api2/multi_thread_executor.h new file mode 100644 index 00000000..f910bbc4 --- /dev/null +++ b/cpp/platform/api2/multi_thread_executor.h @@ -0,0 +1,23 @@ +#ifndef PLATFORM_API2_MULTI_THREAD_EXECUTOR_H_ +#define PLATFORM_API2_MULTI_THREAD_EXECUTOR_H_ + +#include "platform/api2/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- +template +class MultiThreadExecutor + : public SubmittableExecutor { + public: + ~MultiThreadExecutor() override {} +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_MULTI_THREAD_EXECUTOR_H_ diff --git a/cpp/platform/api2/mutex.h b/cpp/platform/api2/mutex.h new file mode 100644 index 00000000..d4dbaf61 --- /dev/null +++ b/cpp/platform/api2/mutex.h @@ -0,0 +1,22 @@ +#ifndef PLATFORM_API2_MUTEX_H_ +#define PLATFORM_API2_MUTEX_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 Mutex { + public: + virtual ~Mutex() {} + + virtual void Lock() = 0; + virtual void Unlock() = 0; +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_MUTEX_H_ diff --git a/cpp/platform/api2/output_file.h b/cpp/platform/api2/output_file.h new file mode 100644 index 00000000..4ac962e8 --- /dev/null +++ b/cpp/platform/api2/output_file.h @@ -0,0 +1,20 @@ +#ifndef PLATFORM_API2_OUTPUT_FILE_H_ +#define PLATFORM_API2_OUTPUT_FILE_H_ + +#include "platform/api2/output_stream.h" +#include "platform/byte_array.h" +#include "platform/exception.h" + +namespace location { +namespace nearby { + +// An OutputFile represents a writable file on the system. +class OutputFile : public OutputStream { + public: + ~OutputFile() override = default; +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_OUTPUT_FILE_H_ diff --git a/cpp/platform/api2/output_stream.h b/cpp/platform/api2/output_stream.h new file mode 100644 index 00000000..b9336ad1 --- /dev/null +++ b/cpp/platform/api2/output_stream.h @@ -0,0 +1,25 @@ +#ifndef PLATFORM_API2_OUTPUT_STREAM_H_ +#define PLATFORM_API2_OUTPUT_STREAM_H_ + +#include "platform/byte_array.h" +#include "platform/exception.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() {} + + virtual Exception Write(const ByteArray& data) = 0; // throws Exception::kIo + virtual Exception Flush() = 0; // throws Exception::kIo + virtual Exception Close() = 0; // throws Exception::kIo +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_OUTPUT_STREAM_H_ diff --git a/cpp/platform/api2/scheduled_executor.h b/cpp/platform/api2/scheduled_executor.h new file mode 100644 index 00000000..ae773ee1 --- /dev/null +++ b/cpp/platform/api2/scheduled_executor.h @@ -0,0 +1,29 @@ +#ifndef PLATFORM_API2_SCHEDULED_EXECUTOR_H_ +#define PLATFORM_API2_SCHEDULED_EXECUTOR_H_ + +#include +#include + +#include "platform/api2/executor.h" +#include "platform/cancelable.h" +#include "platform/runnable.h" +#include "absl/time/time.h" + +namespace location { +namespace nearby { + +// 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; + virtual std::unique_ptr Schedule( + std::unique_ptr runnable, absl::Duration duration) = 0; +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_SCHEDULED_EXECUTOR_H_ diff --git a/cpp/platform/api2/server_sync.h b/cpp/platform/api2/server_sync.h new file mode 100644 index 00000000..47bc3aa5 --- /dev/null +++ b/cpp/platform/api2/server_sync.h @@ -0,0 +1,60 @@ +#ifndef PLATFORM_API2_SERVER_SYNC_H_ +#define PLATFORM_API2_SERVER_SYNC_H_ + +#include + +#include "platform/byte_array.h" +#include "absl/strings/string_view.h" + +namespace location { +namespace nearby { + +// 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 nearby +} // namespace location + +#endif // PLATFORM_API2_SERVER_SYNC_H_ diff --git a/cpp/platform/api2/settable_future.h b/cpp/platform/api2/settable_future.h new file mode 100644 index 00000000..2089173c --- /dev/null +++ b/cpp/platform/api2/settable_future.h @@ -0,0 +1,24 @@ +#ifndef PLATFORM_API2_SETTABLE_FUTURE_H_ +#define PLATFORM_API2_SETTABLE_FUTURE_H_ + +#include "platform/api2/listenable_future.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 +template +class SettableFuture : public ListenableFuture { + public: + ~SettableFuture() override = default; + + virtual bool Set(const T& value) = 0; + virtual bool SetException(Exception exception) = 0; +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_SETTABLE_FUTURE_H_ diff --git a/cpp/platform/api2/single_thread_executor.h b/cpp/platform/api2/single_thread_executor.h new file mode 100644 index 00000000..990f2fe7 --- /dev/null +++ b/cpp/platform/api2/single_thread_executor.h @@ -0,0 +1,23 @@ +#ifndef PLATFORM_API2_SINGLE_THREAD_EXECUTOR_H_ +#define PLATFORM_API2_SINGLE_THREAD_EXECUTOR_H_ + +#include "platform/api2/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-- +template +class SingleThreadExecutor + : public SubmittableExecutor { + public: + ~SingleThreadExecutor() override {} +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_SINGLE_THREAD_EXECUTOR_H_ diff --git a/cpp/platform/api2/socket.h b/cpp/platform/api2/socket.h new file mode 100644 index 00000000..0f855609 --- /dev/null +++ b/cpp/platform/api2/socket.h @@ -0,0 +1,25 @@ +#ifndef PLATFORM_API2_SOCKET_H_ +#define PLATFORM_API2_SOCKET_H_ + +#include "platform/api2/input_stream.h" +#include "platform/api2/output_stream.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 InputStream& GetInputStream() = 0; + virtual OutputStream& GetOutputStream() = 0; + virtual void Close() = 0; +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_SOCKET_H_ diff --git a/cpp/platform/api2/submittable_executor.h b/cpp/platform/api2/submittable_executor.h new file mode 100644 index 00000000..43f16f56 --- /dev/null +++ b/cpp/platform/api2/submittable_executor.h @@ -0,0 +1,42 @@ +#ifndef PLATFORM_API2_SUBMITTABLE_EXECUTOR_H_ +#define PLATFORM_API2_SUBMITTABLE_EXECUTOR_H_ + +#include + +#include "platform/api2/executor.h" +#include "platform/api2/future.h" +#include "platform/callable.h" + +namespace location { +namespace nearby { + +// Each per-platform concrete implementation is expected to extend from +// SubmittableExecutor and provide an override of its submit() method. +// +// e.g. +// class XyzSubmittableExecutor +// : public SubmittableExecutor { +// public: +// template +// std::unique_ptr> submit(std::unique_ptr> callable) { +// ... +// } +// } +template +class SubmittableExecutor : public Executor { + public: + ~SubmittableExecutor() override {} + + template + std::unique_ptr> Submit(std::unique_ptr> callable) { + static_assert( + std::is_base_of_v, + "Class template type is not derived from SubmittableExecutor"); + return static_cast(this)->submit(callable); + } +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_SUBMITTABLE_EXECUTOR_H_ diff --git a/cpp/platform/api2/system_clock.h b/cpp/platform/api2/system_clock.h new file mode 100644 index 00000000..3b0b8090 --- /dev/null +++ b/cpp/platform/api2/system_clock.h @@ -0,0 +1,22 @@ +#ifndef PLATFORM_API2_SYSTEM_CLOCK_H_ +#define PLATFORM_API2_SYSTEM_CLOCK_H_ + +#include + +#include "absl/time/time.h" + +namespace location { +namespace nearby { + +class SystemClock final { + public: + // 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. + static absl::Time ElapsedRealtime(); +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_SYSTEM_CLOCK_H_ diff --git a/cpp/platform/api2/thread_utils.h b/cpp/platform/api2/thread_utils.h new file mode 100644 index 00000000..990c0ec2 --- /dev/null +++ b/cpp/platform/api2/thread_utils.h @@ -0,0 +1,22 @@ +#ifndef PLATFORM_API2_THREAD_UTILS_H_ +#define PLATFORM_API2_THREAD_UTILS_H_ + +#include + +#include "platform/exception.h" +#include "absl/time/time.h" + +namespace location { +namespace nearby { + +class ThreadUtils final { + public: + // https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#sleep(long) + // throws Exception::kInterrupted + static Exception Sleep(absl::Duration timeout); +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_THREAD_UTILS_H_ diff --git a/cpp/platform/api2/webrtc.h b/cpp/platform/api2/webrtc.h new file mode 100644 index 00000000..e1dbde9e --- /dev/null +++ b/cpp/platform/api2/webrtc.h @@ -0,0 +1,46 @@ +#ifndef PLATFORM_API2_WEBRTC_H_ +#define PLATFORM_API2_WEBRTC_H_ + +#include + +#include "platform/byte_array.h" +#include "webrtc/files/stable/webrtc/api/peer_connection_interface.h" + +namespace location { +namespace nearby { + +class WebRtcSignalingMessenger { + public: + virtual ~WebRtcSignalingMessenger() = default; + + /** Called whenever we receive an inbox message from tachyon. */ + class SignalingMessageListener { + public: + virtual ~SignalingMessageListener() = default; + + virtual void OnSignalingMessage(const ByteArray& 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(std::string_view peer_id, + const ByteArray& message) = 0; + virtual bool StartReceivingMessages( + const SignalingMessageListener& listener) = 0; + virtual void GetIceServers( + const IceServersListener& ice_servers_listener) = 0; +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API2_WEBRTC_H_ diff --git a/cpp/platform/api2/wifi.h b/cpp/platform/api2/wifi.h new file mode 100644 index 00000000..74f0e5c9 --- /dev/null +++ b/cpp/platform/api2/wifi.h @@ -0,0 +1,88 @@ +#ifndef PLATFORM_API2_WIFI_H_ +#define PLATFORM_API2_WIFI_H_ + +#include +#include +#include + +#include "absl/strings/string_view.h" + +namespace location { +namespace nearby { + +// 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() {} + + // 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() {} + + 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 nearby +} // namespace location + +#endif // PLATFORM_API2_WIFI_H_ diff --git a/cpp/platform/base64_utils.cc b/cpp/platform/base64_utils.cc index 51cb5635..4ac6e6d6 100644 --- a/cpp/platform/base64_utils.cc +++ b/cpp/platform/base64_utils.cc @@ -1,6 +1,5 @@ #include "platform/base64_utils.h" -#include "strings/escaping.h" #include "absl/strings/escaping.h" namespace location { @@ -25,7 +24,7 @@ std::string Base64Utils::encode(const ByteArray& bytes) { return base64_string; } -std::string Base64Utils::encode(const std::string& input) { +std::string Base64Utils::encode(absl::string_view input) { std::string base64_string; absl::WebSafeBase64Escape(input, &base64_string); @@ -33,7 +32,7 @@ std::string Base64Utils::encode(const std::string& input) { } template<> -Ptr Base64Utils::decode(const std::string& base64_string) { +Ptr Base64Utils::decode(absl::string_view base64_string) { std::string decoded_string; if (!absl::WebSafeBase64Unescape(base64_string, &decoded_string)) { return Ptr(); @@ -43,7 +42,7 @@ Ptr Base64Utils::decode(const std::string& base64_string) { } template<> -ByteArray Base64Utils::decode(const std::string& base64_string) { +ByteArray Base64Utils::decode(absl::string_view base64_string) { std::string decoded_string; if (!absl::WebSafeBase64Unescape(base64_string, &decoded_string)) { return ByteArray(); diff --git a/cpp/platform/base64_utils.h b/cpp/platform/base64_utils.h index 76b8cb7d..cdfee91e 100644 --- a/cpp/platform/base64_utils.h +++ b/cpp/platform/base64_utils.h @@ -4,23 +4,24 @@ #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(const std::string& input); + 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(const std::string& base64_string); + static T decode(absl::string_view base64_string); template <> - Ptr decode(const std::string& base64_string); + Ptr decode(absl::string_view base64_string); template <> - ByteArray decode(const std::string& base64_string); - static Ptr decode(const std::string& base64_string) { + ByteArray decode(absl::string_view base64_string); + static Ptr decode(absl::string_view base64_string) { return decode>(base64_string); } }; diff --git a/cpp/platform/exception.cc b/cpp/platform/exception.cc deleted file mode 100644 index c5dd53a4..00000000 --- a/cpp/platform/exception.cc +++ /dev/null @@ -1,30 +0,0 @@ -#include "platform/exception.h" - -namespace location { -namespace nearby { - -template -ExceptionOr::ExceptionOr(T result) - : result_(result), exception_(Exception::NONE) {} - -template -ExceptionOr::ExceptionOr(Exception::Value exception) - : result_(), exception_(exception) {} - -template -bool ExceptionOr::ok() const { - return Exception::NONE == exception_; -} - -template -T ExceptionOr::result() const { - return result_; -} - -template -Exception::Value ExceptionOr::exception() const { - return exception_; -} - -} // namespace nearby -} // namespace location diff --git a/cpp/platform/exception.h b/cpp/platform/exception.h index 8b07e565..485f03a3 100644 --- a/cpp/platform/exception.h +++ b/cpp/platform/exception.h @@ -1,21 +1,34 @@ #ifndef PLATFORM_EXCEPTION_H_ #define PLATFORM_EXCEPTION_H_ +#include + namespace location { namespace nearby { struct Exception { - enum Value { + 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, // Operarion did not finish within specified time. }; + Value value {kFailed}; }; -// ExceptionOr models the concept of the return value of a function that might -// throw an exception. +// 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. @@ -36,22 +49,31 @@ struct Exception { template class ExceptionOr { public: - explicit ExceptionOr(T result); - explicit ExceptionOr(Exception::Value exception); + 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; + bool ok() const { return exception_.value == Exception::kSuccess; } - T result() const; - Exception::Value exception() const; + 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::Value exception_; + Exception exception_ {Exception::kFailed}; }; } // namespace nearby } // namespace location -#include "platform/exception.cc" - #endif // PLATFORM_EXCEPTION_H_ diff --git a/cpp/platform/exception_test.cc b/cpp/platform/exception_test.cc new file mode 100644 index 00000000..d36e2d85 --- /dev/null +++ b/cpp/platform/exception_test.cc @@ -0,0 +1,76 @@ +#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/default/BUILD b/cpp/platform/impl/default/BUILD index 24d48ca7..87f28f9c 100644 --- a/cpp/platform/impl/default/BUILD +++ b/cpp/platform/impl/default/BUILD @@ -1,8 +1,6 @@ cc_library( name = "default", srcs = [ - "default_condition_variable.cc", - "default_lock.cc", "default_platform.cc", ], hdrs = [ @@ -15,6 +13,8 @@ cc_library( "//core:__subpackages__", ], deps = [ + ":condition_variable", + ":lock", "//platform:types", "//platform/api", ], @@ -38,7 +38,7 @@ cc_library( "//platform:__subpackages__", ], deps = [ - ":default", + ":lock", "//platform:types", "//platform/api:condition_variable", ], diff --git a/cpp/platform/ptr.cc b/cpp/platform/ptr.cc deleted file mode 100644 index 64cbe3c0..00000000 --- a/cpp/platform/ptr.cc +++ /dev/null @@ -1,13 +0,0 @@ -#include "platform/ptr.h" - -namespace location { -namespace nearby { - -namespace ptr_impl { - -const std::int32_t RefCount::kInitialCount = 0; - -} // namespace ptr_impl - -} // namespace nearby -} // namespace location diff --git a/cpp/platform/ptr.h b/cpp/platform/ptr.h index caa9093a..6527db19 100644 --- a/cpp/platform/ptr.h +++ b/cpp/platform/ptr.h @@ -4,78 +4,15 @@ #include #include #include +#include +#include -#include "platform/impl/default/default_lock.h" #include "platform/logging.h" #include "platform/port/down_cast.h" namespace location { namespace nearby { -namespace ptr_impl { - -class RefCount { - public: - RefCount() : lock_(), count_(kInitialCount) {} - - // Returns false if this operation doesn't make conceptual sense any more - // (for example, if it leads to bringing count_ back from the dead). - bool increment() { - bool result; - - lock_.lock(); - { - // Avoid coming back from the dead. - if (count_ < kInitialCount) { - result = false; - } else { - count_++; - result = true; - } - } - lock_.unlock(); - - return result; - } - - // Returns true if after this operation, count_ is 0. - bool decrement() { - bool result; - - lock_.lock(); - { - // It's alright for count_ to go negative because it will only be exactly - // 0 once (since increment() makes sure that once you go negative, you - // can't come back from the dead). - count_--; - result = (count_ == 0); - } - lock_.unlock(); - - return result; - } - - private: - static const std::int32_t kInitialCount; - - DefaultLock lock_; - std::int32_t count_; -}; - -} // namespace ptr_impl - -template -class ObjectDestroyer { - public: - static void destroy(T* t) { delete t; } -}; - -template -class ArrayDestroyer { - public: - static void destroy(T* t) { delete[] t; } -}; - // Forward declarations to make it possible for Ptr (a class template) to // declare ConstifyPtr, DowncastPtr, and DowncastConstPtr (function templates) // as friends. @@ -85,7 +22,7 @@ class ArrayDestroyer { // Ptr (which is what one might reasonably expect). // // See https://isocpp.org/wiki/faq/templates#template-friends for more. -template class Destroyer = ObjectDestroyer> +template class Ptr; template class ConstPtr; @@ -96,128 +33,74 @@ Ptr DowncastPtr(Ptr base_ptr); template ConstPtr DowncastConstPtr(ConstPtr base_ptr); -// A layer of indirection over a raw pointer, to buy flexibility in the -// future to use, for instance: -// -// a) the in-built shared_ptr in modern implementations of C++, -// b) a custom reference-counting mechanism, etc. -// -// , all without having to touch every line of our codebase that uses -// pointers. -// -// Destroyer defines how the owned pointee should be destroyed, and is -// expected to be a class template that provides at least a destroy() -// method, like so: -// -// template -// class MyDestroyer { -// public: -// static void destroy(T* t); -// }; -// -// It defaults to ObjectDestroyer. -template class Destroyer> +// 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() : pointee_(nullptr), ref_count_(nullptr) {} - explicit Ptr(T* pointee, bool is_ref_counted = false, - ptr_impl::RefCount* ref_count = nullptr) - : pointee_(pointee), - ref_count_( - is_ref_counted - ? (ref_count != nullptr ? ref_count : new ptr_impl::RefCount()) - : nullptr) { - init(); - } - Ptr(const Ptr& that) : pointee_(that.pointee_), ref_count_(that.ref_count_) { - init(); - } + Ptr() = default; + explicit Ptr(T* pointee) : ptr_(pointee) {} + Ptr(const Ptr& that) = default; - Ptr& operator=(const Ptr& other) { - if (pointee_ != other.pointee_) { - // If we're not currently ref-counted, then an assignment shouldn't lead - // to any destruction of our past state -- that's the responsibility of - // whichever instance of Ptr believes it owns pointee_. - destroy(false); + Ptr(std::shared_ptr ptr) : ptr_(ptr) {} // NOLINT - pointee_ = other.pointee_; - ref_count_ = other.ref_count_; - - init(); - } + 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() { - return Ptr(pointee_, isRefCounted(), ref_count_); + operator Ptr() { // NOLINT + return Ptr(std::static_pointer_cast(this->ptr_)); + } + operator Ptr() { // NOLINT + return Ptr(*this); } - ~Ptr() { - if (isRefCounted()) { - destroy(); - } else { - // Left empty on purpose. - } - } + explicit operator std::shared_ptr() { return this->ptr_; } + + ~Ptr() = default; bool operator==(const Ptr& other) const { - assert(!(this->isNull())); - assert(!(other.isNull())); - - return ((*(this->pointee_) == *(other.pointee_)) && - (this->isRefCounted() == other.isRefCounted())); + return *(this->ptr_) == *(other.ptr_); } - bool operator!=(const Ptr& other) const { return !(*this == other); } bool operator<(const Ptr& other) const { - assert(!(this->isNull())); - assert(!(other.isNull())); - - return *(this->pointee_) < *(other.pointee_); + return *(this->ptr_) < *(other.ptr_); } - // Calls Destroyer::destroy() to perform deallocation of pointee_. - void destroy(bool should_destroy_if_not_ref_counted = true) { - bool need_to_destroy = isRefCounted() ? ref_count_->decrement() - : should_destroy_if_not_ref_counted; - if (need_to_destroy) { - delete ref_count_; - Destroyer::destroy(pointee_); - } + // No-op: refcounted objects will be destroyed correctly + ABSL_DEPRECATED("Use c++ smart pointers directly instead of Ptr") + void destroy(bool = true) {} - ref_count_ = NULL; // NOLINT - pointee_ = NULL; // NOLINT - } + // No-op: refcounted objects will be destroyed correctly + ABSL_DEPRECATED("Use c++ smart pointers directly instead of Ptr") + void clear() {} - // Use this function only when the ownership is held by someone else, and this - // Ptr object has no responsibility to destroy it. - void clear() { - if (isRefCounted()) { - NEARBY_LOG(FATAL, "Attempting to invoke clear() on a RefCounted Ptr."); - } + T& operator*() const { return *ptr_; } - pointee_ = NULL; // NOLINT - } + T* operator->() const { return ptr_.get(); } + T* get() { return ptr_.get(); } + void reset() { return ptr_.reset(); } - T& operator*() const { - assert(pointee_ != NULL); // NOLINT - return *pointee_; - } + ABSL_DEPRECATED("Use c++ smart pointers directly instead of Ptr") + bool isNull() const { return !this->ptr_; } - T* operator->() const { - assert(pointee_ != NULL); // NOLINT - return pointee_; - } - - bool isNull() const { return pointee_ == nullptr; } - bool isRefCounted() const { return ref_count_ != nullptr; } + // 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 @@ -227,16 +110,7 @@ class Ptr { template friend ConstPtr DowncastConstPtr(ConstPtr base_ptr); - void init() { - if (isRefCounted()) { - if (!ref_count_->increment()) { - NEARBY_LOG(FATAL, "Failed to increment RefCount."); - } - } - } - - T* pointee_; - ptr_impl::RefCount* ref_count_; + std::shared_ptr ptr_; }; // Convenience wrapper for a read-only version of Ptr (in which the pointee @@ -259,9 +133,9 @@ template class ConstPtr : public Ptr { public: ConstPtr() {} - explicit ConstPtr(T* pointee, bool is_ref_counted = false, - ptr_impl::RefCount* ref_count = nullptr) - : Ptr(pointee, is_ref_counted, ref_count) {} + 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 @@ -291,33 +165,29 @@ class ScopedPtr { public: explicit ScopedPtr(typename PtrType::PointeeType* pointee) : ptr_(pointee) {} explicit ScopedPtr(PtrType ptr) : ptr_(ptr) {} - ~ScopedPtr() { ptr_.destroy(); } + ScopedPtr(const ScopedPtr&) = delete; + ~ScopedPtr() = default; + + ScopedPtr& operator=(const ScopedPtr&) = delete; // Shadow methods for the underlying Ptr. - typename PtrType::PointeeType& operator*() const { return ptr_.operator*(); } + 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 ptr_; } + PtrType get() const { return this->ptr_; } - // Releases the underlying Ptr from the clutches of this ScopedPtr, - // effectively resetting this ScopedPtr (and making its destructor be a no-op) - // -- useful for transfer of ownership from one ScopedPtr to another across - // scopes. + // Does nothing; + // this is to avoid unintended destruction of a managed pointer. + // TODO(b/149938110): remove this completely. PtrType release() { - PtrType released = ptr_; - ptr_ = PtrType(); - return released; + return ptr_; } private: - // Disallow copy and assignment. - ScopedPtr(const ScopedPtr&); - ScopedPtr& operator=(const ScopedPtr&); - PtrType ptr_; }; @@ -358,19 +228,19 @@ ConstPtr MakeConstPtr(T* raw_ptr) { // reference). template Ptr MakeRefCountedPtr(T* raw_ptr) { - return Ptr(raw_ptr, true); + return Ptr(raw_ptr); } // ConstPtr counterpart to MakeRefCountedPtr(). template ConstPtr MakeRefCountedConstPtr(T* raw_ptr) { - return ConstPtr(raw_ptr, true); + return ConstPtr(raw_ptr); } // Use this function to convert a Ptr object to a ConstPtr object. template ConstPtr ConstifyPtr(Ptr ptr) { - return ConstPtr(ptr.pointee_, ptr.isRefCounted(), ptr.ref_count_); + return ConstPtr(ptr); } // Use this function to downcast from a Ptr to a Ptr. @@ -382,16 +252,16 @@ ConstPtr ConstifyPtr(Ptr ptr) { // Ptr my_child_ptr = DowncastPtr(my_base_ptr); template Ptr DowncastPtr(Ptr base_ptr) { - return Ptr(DOWN_CAST(base_ptr.pointee_), - base_ptr.isRefCounted(), base_ptr.ref_count_); + static_assert(std::is_base_of_v); + 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_v); return ConstPtr( - const_cast(DOWN_CAST(base_ptr.pointee_)), - base_ptr.isRefCounted(), base_ptr.ref_count_); + std::static_pointer_cast(base_ptr.ptr_)); } } // namespace nearby diff --git a/cpp/platform/ptr_test.cc b/cpp/platform/ptr_test.cc index a68a58b9..adc73c08 100644 --- a/cpp/platform/ptr_test.cc +++ b/cpp/platform/ptr_test.cc @@ -22,15 +22,6 @@ TEST(PtrTest, RefCountedPtr_MultipleReferences) { SUCCEED(); } -TEST(PtrTest, RefCountedPtr_IsRefCounted_Works) { - Ptr ref_counted = MakeRefCountedPtr(new int(1234)); - Ptr manually_counted = MakePtr(new int(1234)); - ScopedPtr > scoped_manually_counted(manually_counted); - - ASSERT_TRUE(ref_counted.isRefCounted()); - ASSERT_FALSE(manually_counted.isRefCounted()); -} - TEST(PtrTest, RefCountedPtr_MultipleReferencesWithScoped) { Ptr ref_counted = MakeRefCountedPtr(new int(1234)); ScopedPtr > scoped_ref_counted_1(ref_counted); @@ -51,60 +42,6 @@ TEST(PtrTest, AssignmentOperator_RefCountedToRefCounted) { ASSERT_EQ(1234, *ref_counted_2); } -TEST(PtrTest, AssignmentOperator_ManuallyCountedToManuallyCounted) { - Ptr manually_counted_1 = MakePtr(new int(1234)); - Ptr manually_counted_2 = MakePtr(new int(5678)); - // Avoid leaks. - ScopedPtr > scoped_manually_counted_1(manually_counted_1); - ScopedPtr > scoped_manually_counted_2(manually_counted_2); - - manually_counted_2 = manually_counted_1; - - ASSERT_EQ(1234, *manually_counted_1); - ASSERT_EQ(1234, *manually_counted_2); - ASSERT_EQ(1234, *scoped_manually_counted_1); - ASSERT_EQ(5678, *scoped_manually_counted_2); -} - -TEST(PtrTest, AssignmentOperator_RefCountedToManuallyCounted) { - Ptr ref_counted = MakeRefCountedPtr(new int(1234)); - Ptr manually_counted = MakePtr(new int(5678)); - // Avoid leaks. - ScopedPtr > scoped_manually_counted(manually_counted); - - manually_counted = ref_counted; - - ASSERT_EQ(1234, *ref_counted); - ASSERT_EQ(1234, *manually_counted); - ASSERT_EQ(5678, *scoped_manually_counted); -} - -TEST(PtrTest, AssignmentOperator_ManuallyCountedToRefCounted) { - Ptr manually_counted = MakePtr(new int(1234)); - Ptr ref_counted = MakeRefCountedPtr(new int(5678)); - // Avoid leaks. - ScopedPtr > scoped_manually_counted(manually_counted); - - ref_counted = manually_counted; - - ASSERT_EQ(1234, *ref_counted); - ASSERT_EQ(1234, *manually_counted); - ASSERT_EQ(1234, *scoped_manually_counted); -} - -TEST(PtrTest, AssignmentOperator_SelfAssignment_ManuallyCounted) { - Ptr manually_counted_1 = MakePtr(new int(1234)); - Ptr manually_counted_2(manually_counted_1); - // Avoid leaks. - ScopedPtr > scoped_manually_counted_1(manually_counted_1); - - manually_counted_1 = manually_counted_2; - - ASSERT_EQ(1234, *manually_counted_1); - ASSERT_EQ(1234, *manually_counted_2); - ASSERT_EQ(1234, *scoped_manually_counted_1); -} - TEST(PtrTest, AssignmentOperator_SelfAssignment_RefCounted) { Ptr ref_counted_1 = MakeRefCountedPtr(new int(1234)); Ptr ref_counted_2(ref_counted_1); @@ -115,19 +52,6 @@ TEST(PtrTest, AssignmentOperator_SelfAssignment_RefCounted) { ASSERT_EQ(1234, *ref_counted_2); } -TEST(PtrTest, EqualityOperator_ManuallyCounted) { - Ptr manually_counted_1 = MakePtr(new int(1234)); - Ptr manually_counted_2(manually_counted_1); - // Avoid leaks. - ScopedPtr > scoped_manually_counted_1(manually_counted_1); - - ASSERT_TRUE(manually_counted_1 == manually_counted_2); - - manually_counted_1 = manually_counted_2; - - ASSERT_TRUE(manually_counted_1 == manually_counted_2); -} - TEST(PtrTest, EqualityOperator_RefCounted) { Ptr ref_counted_1 = MakeRefCountedPtr(new int(1234)); Ptr ref_counted_2(ref_counted_1); @@ -139,16 +63,6 @@ TEST(PtrTest, EqualityOperator_RefCounted) { ASSERT_TRUE(ref_counted_1 == ref_counted_2); } -TEST(PtrTest, EqualityOperator_ManuallyAndRefCounted) { - int* raw = new int(1234); - Ptr manually_counted = MakePtr(raw); - Ptr ref_counted = MakeRefCountedPtr(raw); - // No need for a ScopedPtr for manually_counted here because we know that - // ref_counted will take care of deallocating 'raw'. - - ASSERT_FALSE(manually_counted == ref_counted); -} - namespace { class Base { @@ -171,17 +85,6 @@ class Derived : public Base { } // namespace -TEST(PtrTest, DerivedToBaseConversion_ManuallyCounted) { - Ptr derived = MakePtr(new Derived(1234)); - Ptr base = derived; - // Avoid leaks. - ScopedPtr > scoped_derived(derived); - - ASSERT_EQ(1234, base->getInt()); - ASSERT_EQ(1234, derived->getInt()); - ASSERT_EQ(1234, scoped_derived->getInt()); -} - TEST(PtrTest, DerivedToBaseConversion_RefCounted) { Ptr derived = MakeRefCountedPtr(new Derived(1234)); Ptr base = derived; @@ -193,17 +96,18 @@ TEST(PtrTest, DerivedToBaseConversion_RefCounted) { ASSERT_EQ(1234, base->getInt()); } -TEST(PtrTest, ScopedPtr_Release_ManuallyCounted) { - Ptr manually_counted_1 = MakePtr(new int(1234)); - ScopedPtr > scoped_manually_counted_1(manually_counted_1); +TEST(PtrTest, DistinctValuesAreNotEqual) { + Ptr value1 = MakePtr(new int(5)); + Ptr value2 = MakePtr(new int(6)); - Ptr manually_counted_2 = scoped_manually_counted_1.release(); - // Avoid leaks. - ScopedPtr > scoped_manually_counted_2(manually_counted_2); + ASSERT_NE(value1, value2); +} - ASSERT_TRUE(scoped_manually_counted_1.isNull()); - ASSERT_EQ(1234, *manually_counted_2); - ASSERT_EQ(1234, *scoped_manually_counted_2); +TEST(PtrTest, SameValuesAreEqual) { + Ptr value1 = MakePtr(new int(5)); + Ptr value2 = MakePtr(new int(5)); + + ASSERT_EQ(value1, value2); } TEST(PtrTest, ScopedPtr_Release_RefCounted) { @@ -212,20 +116,20 @@ TEST(PtrTest, ScopedPtr_Release_RefCounted) { Ptr ref_counted_2 = scoped_ref_counted_1.release(); - ASSERT_TRUE(scoped_ref_counted_1.isNull()); + ASSERT_EQ(*scoped_ref_counted_1, *ref_counted_2); ASSERT_EQ(1234, *ref_counted_2); } -TEST(PtrTest, ConstifyPtr_ManuallyCounted) { - Ptr manually_counted = MakePtr(new int(1234)); - // Avoid leaks. - ScopedPtr > scoped_manually_counted(manually_counted); +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); - ConstPtr const_manually_counted = ConstifyPtr(manually_counted); + Ptr ref_counted_3 = scoped_ref_counted_1.release(); - ASSERT_EQ(1234, *const_manually_counted); - ASSERT_EQ(1234, *manually_counted); - ASSERT_EQ(1234, *scoped_manually_counted); + ASSERT_EQ(*scoped_ref_counted_1, *ref_counted_3); + ASSERT_EQ(1234, *ref_counted_2); + ASSERT_EQ(1234, *ref_counted_3); } TEST(PtrTest, ConstifyPtr_RefCounted) { @@ -240,19 +144,6 @@ TEST(PtrTest, ConstifyPtr_RefCounted) { ASSERT_EQ(1234, *const_ref_counted); } -TEST(PtrTest, DowncastPtr_ManuallyCounted) { - Ptr derived = MakePtr(new Derived(1234)); - Ptr base = derived; - // Avoid leaks. - ScopedPtr > scoped_derived(derived); - - Ptr derived_from_downcast = DowncastPtr(base); - - ASSERT_EQ(1234, base->getInt()); - ASSERT_EQ(1234, derived->getInt()); - ASSERT_EQ(1234, derived_from_downcast->getInt()); -} - TEST(PtrTest, DowncastPtr_RefCounted) { Ptr derived = MakeRefCountedPtr(new Derived(1234)); Ptr base = derived; diff --git a/proto/BUILD b/proto/BUILD index 62d9d917..6446d8f9 100644 --- a/proto/BUILD +++ b/proto/BUILD @@ -13,12 +13,6 @@ proto_library( deps = ["//logs/proto/logs_annotations"], ) -cc_proto_library( - name = "bootstrap_enums_cc_proto", - compatible_with = ["//buildenv/target:appengine"], - deps = [":bootstrap_enums_proto"], -) - java_lite_proto_library( name = "bootstrap_enums_java_proto_lite", visibility = [ @@ -35,12 +29,6 @@ proto_library( deps = ["//logs/proto/logs_annotations"], ) -cc_proto_library( - name = "discovery_enums_cc_proto", - compatible_with = ["//buildenv/target:appengine"], - deps = [":discovery_enums_proto"], -) - java_lite_proto_library( name = "discovery_enums_java_proto_lite", deps = [":discovery_enums_proto"], @@ -62,12 +50,6 @@ proto_library( ], ) -cc_proto_library( - name = "connections_enums_cc_proto", - compatible_with = ["//buildenv/target:appengine"], - deps = [":connections_enums_proto"], -) - java_lite_proto_library( name = "connections_enums_java_proto_lite", deps = [":connections_enums_proto"], @@ -108,12 +90,6 @@ proto_library( ], ) -cc_proto_library( - name = "setup_enums_cc_proto", - compatible_with = ["//buildenv/target:appengine"], - deps = [":setup_enums_proto"], -) - java_lite_proto_library( name = "setup_enums_java_proto_lite", deps = [":setup_enums_proto"], @@ -129,12 +105,6 @@ proto_library( ], ) -cc_proto_library( - name = "nearby_client_enums_cc_proto", - compatible_with = ["//buildenv/target:appengine"], - deps = [":nearby_client_enums_proto"], -) - java_lite_proto_library( name = "nearby_client_enums_java_proto_lite", deps = [":nearby_client_enums_proto"], @@ -181,12 +151,6 @@ proto_library( ], ) -cc_proto_library( - name = "sharing_enums_cc_proto", - compatible_with = ["//buildenv/target:appengine"], - deps = [":sharing_enums_proto"], -) - java_lite_proto_library( name = "sharing_enums_java_proto_lite", deps = [":sharing_enums_proto"], @@ -202,12 +166,6 @@ proto_library( ], ) -cc_proto_library( - name = "nearby_event_codes_cc_proto", - compatible_with = ["//buildenv/target:appengine"], - deps = [":nearby_event_codes_proto"], -) - java_lite_proto_library( name = "nearby_event_codes_java_proto_lite", deps = [":nearby_event_codes_proto"], diff --git a/proto/connections/BUILD b/proto/connections/BUILD index 90411711..c7c295c2 100644 --- a/proto/connections/BUILD +++ b/proto/connections/BUILD @@ -1,4 +1,3 @@ -load("//tools/build_defs/proto/cpp:cc_proto_library.bzl", "cc_proto_library") load("//net/proto2/contrib/portable/cc:portable_proto_build_defs.bzl", "portable_proto_library") proto_library( @@ -10,16 +9,6 @@ proto_library( visibility = ["//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__"], ) -cc_proto_library( - name = "offline_wire_formats_cc_proto", - visibility = [ - "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", - "//java/com/google/android/gmscore/integ/modules/nearby/src/com/google/android/gms/nearby/connection:__subpackages__", - "//javatests/com/google/android/gmscore/integ/modules/nearby/robolectric/connections/src/com/google/android/gms/nearby/connection:__subpackages__", - ], - deps = [":offline_wire_formats_proto"], -) - java_lite_proto_library( name = "offline_wire_formats_java_proto_lite", visibility = [ diff --git a/proto/connections_enums.proto b/proto/connections_enums.proto index f4eaaa2a..461d312c 100644 --- a/proto/connections_enums.proto +++ b/proto/connections_enums.proto @@ -1,3 +1,14 @@ +// Any changes in this file maybe cause the unmapped result in the PLX tables. +// Please remember to update the table schemas: +// 1. Check your changes are rolled out in the MPM. +// https://mpmbrowse.corp.google.com/package/location/nearby/lingo +// 2. Check the new lingo job is scheduled and completed. +// https://borgcron-dashboard.corp.google.com/#user=social-copresence-batch +// 3. Runs PLX script to update schema. +// https://plx.corp.google.com/scripts2/script_e1._9eb6f3_e3cd_419b_b483_c1e42abc824a +// +// Or you can wait one or two days then run the above Step3. dircetly. + syntax = "proto2"; package location.nearby.proto.connections; @@ -149,6 +160,7 @@ enum PayloadStatus { REMOTE_CANCELLATION = 8; } +// next_id: 16 // Result of an upgrade attempt. enum BandwidthUpgradeResult { UNKNOWN_BANDWIDTH_UPGRADE_RESULT = 0; @@ -177,10 +189,26 @@ enum BandwidthUpgradeResult { // record analytics (e.g. the client disconnected). UNFINISHED_ERROR = 10; - // TODO(mariaines): add a REMOTE_ERROR when we implement a cancellation + // TODO(b/151833661): add a REMOTE_ERROR when we implement a cancellation // message, for the case when the remote endpoint had an error on their end. + + // Error during setting up Bluetooth. + BLUETOOTH_MEDIUM_ERROR = 11; + + // Error during setting up WIFI Aware. + WIFI_AWARE_MEDIUM_ERROR = 12; + + // Error during setting up WIFI Lan. + WIFI_LAN_MEDIUM_ERROR = 13; + + // Error during setting up WIFI Hotspot. + WIFI_HOTSPOT_MEDIUM_ERROR = 14; + + // Error during setting up WIFI Direct. + WIFI_DIRECT_MEDIUM_ERROR = 15; } +// next_id: 34 // The stage at which an error occurred. enum BandwidthUpgradeErrorStage { UNKNOWN_BANDWIDTH_UPGRADE_ERROR_STAGE = 0; @@ -211,12 +239,16 @@ enum BandwidthUpgradeErrorStage { WIFI_LISTEN_INCOMING = 11; // On the outgoing side, connecting to the hotspot. WIFI_CONNECT_TO_HOTSPOT = 12; + // Creating the WIFI Hotspot EndpointChannel + WIFI_HOTSPOT_SOCKET_CREATION = 28; // WIFI_LAN // On the incoming side, listening for incoming wifi connections. WIFI_LAN_LISTEN_INCOMING = 13; // On the incoming side, invalid (null or loopback) Inet Address. WIFI_LAN_IP_ADDRESS = 14; + // Creating the WIFI Lan EndpointChannel + WIFI_LAN_SOCKET_CREATION = 29; // On the outgoing side, connecting to the local wifi socket. WIFI_LAN_SOCKET_CONNECTION = 15; @@ -229,6 +261,8 @@ enum BandwidthUpgradeErrorStage { BLUETOOTH_CONNECT_OUTGOING = 18; // On the outgoing side, parsing the remote Bluetooth MAC address. BLUETOOTH_PARSE_MAC_ADDRESS = 19; + // Creating the BLUETOOTH EndpointChannel + BLUETOOTH_SOCKET_CREATION = 30; // WIFI_AWARE // On the incoming side, listening for incoming Wifi Aware connections. @@ -239,6 +273,8 @@ enum BandwidthUpgradeErrorStage { WIFI_AWARE_SUBSCRIBE = 22; // On the outgoing side, connecting to the Wifi Aware network. WIFI_AWARE_CONNECT_TO_NETWORK = 23; + // Creating the WIFI Aware EndpointChannel + WIFI_AWARE_SOCKET_CREATION = 31; // WIFI_DIRECT // On the incoming side, listening for incoming Wifi Direct connections. @@ -249,4 +285,10 @@ enum BandwidthUpgradeErrorStage { WIFI_DIRECT_CONNECT_OUTGOING = 26; // On the outgoing side, parsing the remote device address. WIFI_DIRECT_PARSE_DEVICE_ADDRESS = 27; + // Creating the WIFI Direct EndpointChannel + WIFI_DIRECT_SOCKET_CREATION = 32; + + // WEB_RTC + // Creating the WEB_RTC EndpointChannel + WEB_RTC_SOCKET_CREATION = 33; } diff --git a/proto/discovery_enums.proto b/proto/discovery_enums.proto index 71492b95..08423b4e 100644 --- a/proto/discovery_enums.proto +++ b/proto/discovery_enums.proto @@ -9,7 +9,7 @@ option java_api_version = 2; option java_package = "com.google.location.nearby.proto"; option java_outer_classname = "DiscoveryEnums"; -// NEXT ID: 130 +// NEXT ID: 132 enum DiscoveryEvent { UNKNOWN_DISCOVERY_EVENT = 0; @@ -299,7 +299,8 @@ enum DiscoveryEvent { // containing a bloom filter FAST_PAIR_DEVICE_DETECTED_WITH_BLOOM_FILTER = 103; - // Detected model id was found in the local Fast Pair device database. + // Detected model id was found in the local Fast Pair device database which is + // not populated by the offline service (130 is offline populated). FAST_PAIR_LOCAL_DB_CACHE_HIT = 104; // Detected model id was not found in the local Fast Pair device database, @@ -335,7 +336,7 @@ enum DiscoveryEvent { // scan stack. FAST_PAIR_NOTIFICATION_CLICKED = 113; - // User has seen a battery notification. + // User has seen a battery notification (131 for low battery). FAST_PAIR_BATTERY_NOTIFICATION_SHOWN = 114; // User has dismissed the battery notification. @@ -385,6 +386,13 @@ enum DiscoveryEvent { // A user dismissed event of launching a companion app. FAST_PAIR_POST_ACTION_DISMISS_COMPANION_APP = 129; + // Detected model id was found in the cache which is populated by the offline + // service (104 is the local db cache). + FAST_PAIR_OFFLINE_SERVICE_CACHE_HIT = 130; + + // User has seen a low battery notification. + FAST_PAIR_LOW_BATTERY_NOTIFICATION_SHOWN = 131; + // Deprecated. reserved 65, 67 to 72; } diff --git a/proto/sharing_enums.proto b/proto/sharing_enums.proto index a1df8808..fd517938 100644 --- a/proto/sharing_enums.proto +++ b/proto/sharing_enums.proto @@ -106,8 +106,8 @@ enum EventType { // Receiver accepts a fast initialization. ACCEPT_FAST_INITIALIZATION = 27; - // Set internet preference. - SET_INTERNET_PREFERENCE = 28; + // Set data usage preference. + SET_DATA_USAGE = 28; } // Status of nearby sharing. @@ -127,8 +127,8 @@ enum Visibility { HIDDEN = 4; } -enum InternetPreference { - UNKNOWN_INTERNET_PREFERENCE = 0; +enum DataUsage { + UNKNOWN_DATA_USAGE = 0; ONLINE = 1; WIFI_ONLY = 2;