Roll forward to cl/314747126

Signed-off-by: Alexey Polyudov <apolyudov@google.com>
Change-Id: Ie19e006429b138b3768e97dae971a43fdc5ef8bf
This commit is contained in:
Alexey Polyudov
2020-06-04 13:50:45 -07:00
parent de31c27947
commit 4baa1ce96a
365 changed files with 28586 additions and 1503 deletions
+35 -4
View File
@@ -12,6 +12,26 @@
# See the License for the specific language governing permissions and
# limitations under the License.
cc_library(
name = "utils",
srcs = [
"utils.cc",
],
hdrs = [
"utils.h",
],
visibility = [
"//core/internal/mediums/webrtc:__pkg__",
],
deps = [
"//platform:types",
"//platform:utils",
"//platform/api",
"//platform/port:string",
"//absl/strings",
],
)
cc_library(
name = "mediums",
srcs = [
@@ -19,8 +39,6 @@ cc_library(
"ble_advertisement_header.cc",
"ble_packet.cc",
"ble_peripheral.cc",
"utils.cc",
"utils.h",
],
hdrs = [
"advertisement_read_result.cc",
@@ -48,9 +66,12 @@ cc_library(
"mediums.h",
"uuid.cc",
"uuid.h",
"wifi_lan.cc",
"wifi_lan.h",
],
visibility = ["//core/internal:__pkg__"],
deps = [
":utils",
"//platform:logging",
"//platform:types",
"//platform:utils",
@@ -67,7 +88,8 @@ cc_test(
srcs = ["advertisement_read_result_test.cc"],
deps = [
":mediums",
"//platform/impl/default",
"//platform/api",
"//platform/impl/g3",
"//testing/base/public:gunit_main",
"//absl/time",
],
@@ -79,6 +101,8 @@ cc_test(
deps = [
":mediums",
"//platform:utils",
"//platform/api",
"//platform/impl/g3",
"//testing/base/public:gunit_main",
],
)
@@ -88,6 +112,8 @@ cc_test(
srcs = ["ble_advertisement_test.cc"],
deps = [
":mediums",
"//platform/api",
"//platform/impl/g3",
"//testing/base/public:gunit_main",
],
)
@@ -97,6 +123,8 @@ cc_test(
srcs = ["ble_packet_test.cc"],
deps = [
":mediums",
"//platform/api",
"//platform/impl/g3",
"//testing/base/public:gunit_main",
],
)
@@ -106,6 +134,8 @@ cc_test(
srcs = ["bloom_filter_test.cc"],
deps = [
":mediums",
"//platform/api",
"//platform/impl/g3",
"//testing/base/public:gunit_main",
],
)
@@ -115,7 +145,8 @@ cc_test(
srcs = ["lost_entity_tracker_test.cc"],
deps = [
":mediums",
"//platform/impl/default",
"//platform/api",
"//platform/impl/g3",
"//testing/base/public:gunit_main",
],
)
+1 -1
View File
@@ -66,7 +66,7 @@ target_link_libraries(core_internal_mediums_test
core_internal_mediums
gtest
gtest_main
platform_impl_default
platform_impl_g3
platform_utils
)
@@ -14,7 +14,7 @@
#include "core/internal/mediums/advertisement_read_result.h"
#include "platform/impl/default/default_platform.h"
#include "platform/api/platform.h"
#include "gtest/gtest.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
@@ -24,23 +24,7 @@ namespace nearby {
namespace connections {
namespace mediums {
class SampleSystemClock : public SystemClock {
public:
SampleSystemClock() {}
~SampleSystemClock() override {}
std::int64_t elapsedRealtime() override {
return absl::ToUnixMillis(absl::Now());
}
};
class SamplePlatform {
public:
static Ptr<Lock> createLock() { return DefaultPlatform::createLock(); }
static Ptr<SystemClock> createSystemClock() {
return MakePtr(new SampleSystemClock());
}
};
using TestPlatform = platform::ImplementationPlatform;
constexpr char kAdvertisementBytes[] = {0x0A, 0x0B, 0x0C};
@@ -53,16 +37,16 @@ const absl::Duration kAdvertisementMaxBackoffDuration =
template <>
const std::int64_t AdvertisementReadResult<
SamplePlatform>::kAdvertisementMaxBackoffDurationMillis =
TestPlatform>::kAdvertisementMaxBackoffDurationMillis =
ToInt64Milliseconds(kAdvertisementMaxBackoffDuration);
template <>
const std::int64_t
AdvertisementReadResult<
SamplePlatform>::kAdvertisementBaseBackoffDurationMillis =
TestPlatform>::kAdvertisementBaseBackoffDurationMillis =
ToInt64Milliseconds(kAdvertisementBaseBackoffDuration);
TEST(AdvertisementReadResultTest, AdvertisementExists) {
AdvertisementReadResult<SamplePlatform> advertisement_read_result;
AdvertisementReadResult<TestPlatform> advertisement_read_result;
advertisement_read_result.recordLastReadStatus(/* is_success= */ true);
std::int32_t slot = 6;
@@ -75,7 +59,7 @@ TEST(AdvertisementReadResultTest, AdvertisementExists) {
}
TEST(AdvertisementReadResultTest, AdvertisementNonExistent) {
AdvertisementReadResult<SamplePlatform> advertisement_read_result;
AdvertisementReadResult<TestPlatform> advertisement_read_result;
advertisement_read_result.recordLastReadStatus(/* is_success= */ true);
std::int32_t slot = 6;
@@ -84,23 +68,23 @@ TEST(AdvertisementReadResultTest, AdvertisementNonExistent) {
}
TEST(AdvertisementReadResultTest, EvaluateRetryStatusInitialized) {
AdvertisementReadResult<SamplePlatform> advertisement_read_result;
AdvertisementReadResult<TestPlatform> advertisement_read_result;
ASSERT_EQ(advertisement_read_result.evaluateRetryStatus(),
AdvertisementReadResult<SamplePlatform>::RetryStatus::RETRY);
AdvertisementReadResult<TestPlatform>::RetryStatus::RETRY);
}
TEST(AdvertisementReadResultTest, EvaluateRetryStatusSuccess) {
AdvertisementReadResult<SamplePlatform> advertisement_read_result;
AdvertisementReadResult<TestPlatform> advertisement_read_result;
advertisement_read_result.recordLastReadStatus(/* is_success= */ true);
ASSERT_EQ(advertisement_read_result.evaluateRetryStatus(),
AdvertisementReadResult<
SamplePlatform>::RetryStatus::PREVIOUSLY_SUCCEEDED);
TestPlatform>::RetryStatus::PREVIOUSLY_SUCCEEDED);
}
TEST(AdvertisementReadResultTest, EvaluateRetryStatusTooSoon) {
AdvertisementReadResult<SamplePlatform> advertisement_read_result;
AdvertisementReadResult<TestPlatform> advertisement_read_result;
advertisement_read_result.recordLastReadStatus(/* is_success= */ false);
// Sleep for some time, but not long enough to warrant a retry.
@@ -108,22 +92,22 @@ TEST(AdvertisementReadResultTest, EvaluateRetryStatusTooSoon) {
absl::ToInt64Milliseconds(kAdvertisementBaseBackoffDuration) / 2));
ASSERT_EQ(advertisement_read_result.evaluateRetryStatus(),
AdvertisementReadResult<SamplePlatform>::RetryStatus::TOO_SOON);
AdvertisementReadResult<TestPlatform>::RetryStatus::TOO_SOON);
}
TEST(AdvertisementReadResultTest, EvaluateRetryStatusRetry) {
AdvertisementReadResult<SamplePlatform> advertisement_read_result;
AdvertisementReadResult<TestPlatform> advertisement_read_result;
advertisement_read_result.recordLastReadStatus(/* is_success= */ false);
// Sleep long enough to warrant a retry.
absl::SleepFor(kAdvertisementBaseBackoffDuration);
ASSERT_EQ(advertisement_read_result.evaluateRetryStatus(),
AdvertisementReadResult<SamplePlatform>::RetryStatus::RETRY);
AdvertisementReadResult<TestPlatform>::RetryStatus::RETRY);
}
TEST(AdvertisementReadResultTest, ReportStatusExponentialBackoff) {
AdvertisementReadResult<SamplePlatform> advertisement_read_result;
AdvertisementReadResult<TestPlatform> advertisement_read_result;
advertisement_read_result.recordLastReadStatus(/* is_success= */ false);
// Record an additional failure so our backoff duration increases.
@@ -134,11 +118,11 @@ TEST(AdvertisementReadResultTest, ReportStatusExponentialBackoff) {
absl::SleepFor(kAdvertisementBaseBackoffDuration);
ASSERT_EQ(advertisement_read_result.evaluateRetryStatus(),
AdvertisementReadResult<SamplePlatform>::RetryStatus::TOO_SOON);
AdvertisementReadResult<TestPlatform>::RetryStatus::TOO_SOON);
}
TEST(AdvertisementReadResultTest, ReportStatusExponentialBackoffMax) {
AdvertisementReadResult<SamplePlatform> advertisement_read_result;
AdvertisementReadResult<TestPlatform> advertisement_read_result;
advertisement_read_result.recordLastReadStatus(/* is_success= */ false);
// Record an absurd amount of failures so we hit the maximum backoff duration.
@@ -151,11 +135,11 @@ TEST(AdvertisementReadResultTest, ReportStatusExponentialBackoffMax) {
absl::SleepFor(kAdvertisementMaxBackoffDuration);
ASSERT_EQ(advertisement_read_result.evaluateRetryStatus(),
AdvertisementReadResult<SamplePlatform>::RetryStatus::RETRY);
AdvertisementReadResult<TestPlatform>::RetryStatus::RETRY);
}
TEST(AdvertisementReadResultTest, GetDurationSinceRead) {
AdvertisementReadResult<SamplePlatform> advertisement_read_result;
AdvertisementReadResult<TestPlatform> advertisement_read_result;
advertisement_read_result.recordLastReadStatus(/* is_success= */ true);
std::int64_t sleepTime = 420;
+2 -2
View File
@@ -474,8 +474,8 @@ void BLEV2<Platform>::stopScanning() {
// TODO(b/112199086) Change to RecurringCancelableAlarm
template <typename Platform>
Ptr<CancelableAlarm<Platform>> BLEV2<Platform>::createOnLostAlarm() {
return Ptr<CancelableAlarm<Platform>>();
Ptr<CancelableAlarm> BLEV2<Platform>::createOnLostAlarm() {
return Ptr<CancelableAlarm>();
}
// Returns true if the device is currently accepting incoming BLE socket
+3 -3
View File
@@ -180,7 +180,7 @@ class BLEV2 {
struct ScanningInfo {
ScanningInfo(const string& service_id,
Ptr<ScanCallbackFacade> scan_callback_facade,
Ptr<CancelableAlarm<Platform>> on_lost_alarm)
Ptr<CancelableAlarm> on_lost_alarm)
: service_id(service_id),
scan_callback_facade(scan_callback_facade),
on_lost_alarm(on_lost_alarm) {}
@@ -191,7 +191,7 @@ class BLEV2 {
const string service_id;
ScopedPtr<Ptr<ScanCallbackFacade>> scan_callback_facade;
// TODO(ahlee): Change to recurring cancelable alarm
ScopedPtr<Ptr<CancelableAlarm<Platform>>> on_lost_alarm;
ScopedPtr<Ptr<CancelableAlarm>> on_lost_alarm;
};
struct AdvertisingInfo {
@@ -250,7 +250,7 @@ class BLEV2 {
Ptr<BLEPeripheralV2> ble_peripheral,
ConstPtr<BLEAdvertisementData> advertisement_data);
void processOnLostTimeout();
Ptr<CancelableAlarm<Platform>> createOnLostAlarm();
Ptr<CancelableAlarm> createOnLostAlarm();
bool isAdvertisementGattServerRunning();
bool startAdvertisementGattServer(const string& service_id,
@@ -14,7 +14,7 @@
#include "core/internal/mediums/lost_entity_tracker.h"
#include "platform/impl/default/default_platform.h"
#include "platform/api/platform.h"
#include "gtest/gtest.h"
namespace location {
@@ -23,6 +23,8 @@ namespace connections {
namespace mediums {
namespace {
using TestPlatform = platform::ImplementationPlatform;
struct TestEntity {
int id;
@@ -32,7 +34,7 @@ struct TestEntity {
};
TEST(LostEntityTracker, NoEntitiesLost) {
LostEntityTracker<DefaultPlatform, TestEntity> lost_entity_tracker;
LostEntityTracker<TestPlatform, TestEntity> lost_entity_tracker;
ScopedPtr<ConstPtr<TestEntity> > entity_1(MakeConstPtr(new TestEntity(1)));
ScopedPtr<ConstPtr<TestEntity> > entity_2(MakeConstPtr(new TestEntity(2)));
ScopedPtr<ConstPtr<TestEntity> > entity_3(MakeConstPtr(new TestEntity(3)));
@@ -55,7 +57,7 @@ TEST(LostEntityTracker, NoEntitiesLost) {
}
TEST(LostEntityTracker, AllEntitiesLost) {
LostEntityTracker<DefaultPlatform, TestEntity> lost_entity_tracker;
LostEntityTracker<TestPlatform, TestEntity> lost_entity_tracker;
ScopedPtr<ConstPtr<TestEntity> > entity_1(MakeConstPtr(new TestEntity(1)));
ScopedPtr<ConstPtr<TestEntity> > entity_2(MakeConstPtr(new TestEntity(2)));
ScopedPtr<ConstPtr<TestEntity> > entity_3(MakeConstPtr(new TestEntity(3)));
@@ -69,7 +71,7 @@ TEST(LostEntityTracker, AllEntitiesLost) {
ASSERT_TRUE(lost_entity_tracker.computeLostEntities().empty());
// Go through a round without rediscovering any entities.
typename LostEntityTracker<DefaultPlatform, TestEntity>::EntitySet
typename LostEntityTracker<TestPlatform, TestEntity>::EntitySet
lost_entities = lost_entity_tracker.computeLostEntities();
ASSERT_TRUE(lost_entities.find(entity_1.get()) != lost_entities.end());
ASSERT_TRUE(lost_entities.find(entity_2.get()) != lost_entities.end());
@@ -77,7 +79,7 @@ TEST(LostEntityTracker, AllEntitiesLost) {
}
TEST(LostEntityTracker, SomeEntitiesLost) {
LostEntityTracker<DefaultPlatform, TestEntity> lost_entity_tracker;
LostEntityTracker<TestPlatform, TestEntity> lost_entity_tracker;
ScopedPtr<ConstPtr<TestEntity> > entity_1(MakeConstPtr(new TestEntity(1)));
ScopedPtr<ConstPtr<TestEntity> > entity_2(MakeConstPtr(new TestEntity(2)));
ScopedPtr<ConstPtr<TestEntity> > entity_3(MakeConstPtr(new TestEntity(3)));
@@ -94,7 +96,7 @@ TEST(LostEntityTracker, SomeEntitiesLost) {
// was lost after the check.
lost_entity_tracker.recordFoundEntity(entity_1.get());
lost_entity_tracker.recordFoundEntity(entity_3.get());
typename LostEntityTracker<DefaultPlatform, TestEntity>::EntitySet
typename LostEntityTracker<TestPlatform, TestEntity>::EntitySet
lost_entities = lost_entity_tracker.computeLostEntities();
ASSERT_TRUE(lost_entities.find(entity_1.get()) == lost_entities.end());
ASSERT_TRUE(lost_entities.find(entity_2.get()) != lost_entities.end());
@@ -102,7 +104,7 @@ TEST(LostEntityTracker, SomeEntitiesLost) {
}
TEST(LostEntityTracker, SameEntityMultipleCopies) {
LostEntityTracker<DefaultPlatform, TestEntity> lost_entity_tracker;
LostEntityTracker<TestPlatform, TestEntity> lost_entity_tracker;
ScopedPtr<ConstPtr<TestEntity> > entity_1(MakeConstPtr(new TestEntity(1)));
ScopedPtr<ConstPtr<TestEntity> > entity_1_copy(
MakeConstPtr(new TestEntity(1)));
@@ -121,7 +123,7 @@ TEST(LostEntityTracker, SameEntityMultipleCopies) {
// Go through a round without rediscovering any entities and verify that we
// lost an entity equivalent to both copies of it.
typename LostEntityTracker<DefaultPlatform, TestEntity>::EntitySet
typename LostEntityTracker<TestPlatform, TestEntity>::EntitySet
lost_entities = lost_entity_tracker.computeLostEntities();
ASSERT_EQ(lost_entities.size(), 1);
ASSERT_TRUE(lost_entities.find(entity_1.get()) != lost_entities.end());
+7 -1
View File
@@ -24,7 +24,8 @@ Mediums<Platform>::Mediums()
bluetooth_classic_(
new BluetoothClassic<Platform>(bluetooth_radio_.get())),
ble_(new BLE<Platform>(bluetooth_radio_.get())),
ble_v2_(new mediums::BLEV2<Platform>(bluetooth_radio_.get())) {}
ble_v2_(new mediums::BLEV2<Platform>(bluetooth_radio_.get())),
wifi_lan_(new mediums::WifiLan<Platform>()) {}
template <typename Platform>
Mediums<Platform>::~Mediums() {
@@ -51,6 +52,11 @@ Ptr<mediums::BLEV2<Platform> > Mediums<Platform>::bleV2() const {
return ble_v2_.get();
}
template <typename Platform>
Ptr<mediums::WifiLan<Platform> > Mediums<Platform>::wifi_lan() const {
return wifi_lan_.get();
}
} // namespace connections
} // namespace nearby
} // namespace location
+4
View File
@@ -19,6 +19,7 @@
#include "core/internal/mediums/ble_v2.h"
#include "core/internal/mediums/bluetooth_classic.h"
#include "core/internal/mediums/bluetooth_radio.h"
#include "core/internal/mediums/wifi_lan.h"
#include "platform/ptr.h"
namespace location {
@@ -41,6 +42,8 @@ class Mediums {
Ptr<BLE<Platform> > ble() const;
// Returns a handle to V2 of the Bluetooth Low Energy (BLE) medium.
Ptr<mediums::BLEV2<Platform> > bleV2() const;
// Returns a handle to the Wifi-Lan medium.
Ptr<mediums::WifiLan<Platform> > wifi_lan() const;
private:
// The order of declaration is critical for both construction and
@@ -55,6 +58,7 @@ class Mediums {
ScopedPtr<Ptr<BluetoothClassic<Platform> > > bluetooth_classic_;
ScopedPtr<Ptr<BLE<Platform> > > ble_;
ScopedPtr<Ptr<mediums::BLEV2<Platform> > > ble_v2_;
ScopedPtr<Ptr<mediums::WifiLan<Platform> > > wifi_lan_;
};
} // namespace connections
+22
View File
@@ -14,9 +14,11 @@
#include "core/internal/mediums/utils.h"
#include <cstdint>
#include <sstream>
#include "platform/exception.h"
#include "platform/prng.h"
#include "absl/strings/escaping.h"
namespace location {
@@ -62,6 +64,26 @@ ConstPtr<ByteArray> Utils::legacySha256HashOnlyForPrinting(
return Utils::sha256Hash(hash_utils, formatted_hex_byte_array.get(), length);
}
ConstPtr<ByteArray> Utils::generateRandomBytes(size_t length) {
Prng rng;
std::string data;
data.reserve(length);
// Adds 4 random bytes per iteration.
while (length > 0) {
std::uint32_t val = rng.nextUInt32();
for (int i = 0; i < 4; i++) {
data += val & 0xFF;
val >>= 8;
length--;
if (!length) break;
}
}
return MakeConstPtr(new ByteArray(data));
}
std::string Utils::bytesToPrintableHexString(ConstPtr<ByteArray> bytes) {
std::string hex_string(
absl::BytesToHexString(std::string(bytes->getData(), bytes->size())));
+2
View File
@@ -35,6 +35,8 @@ class Utils {
static ConstPtr<ByteArray> legacySha256HashOnlyForPrinting(
Ptr<HashUtils> hash_utils, ConstPtr<ByteArray> source, size_t length);
static ConstPtr<ByteArray> generateRandomBytes(size_t length);
private:
static std::string bytesToPrintableHexString(ConstPtr<ByteArray> bytes);
};
+3 -3
View File
@@ -31,17 +31,17 @@ namespace connections {
template <typename Platform>
class UUID {
public:
explicit UUID(const string& data);
explicit UUID(const std::string& data);
UUID(std::int64_t most_sig_bits, std::int64_t least_sig_bits);
~UUID();
// Returns the canonical textual representation
// (https://en.wikipedia.org/wiki/Universally_unique_identifier#Format) of the
// UUID.
string str();
std::string str();
private:
string data_;
std::string data_;
};
} // namespace connections
+91
View File
@@ -0,0 +1,91 @@
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
cc_library(
name = "webrtc",
hdrs = [
"webrtc_socket.cc",
"webrtc_socket.h",
],
deps = [
"//platform:utils",
"//platform/api",
"//webrtc/api:libjingle_peerconnection_api",
],
)
cc_test(
name = "webrtc_test",
srcs = ["webrtc_socket_test.cc"],
deps = [
":webrtc",
"//platform:types",
"//platform/api",
"//platform/impl/g3", # buildcleaner: keep
"//testing/base/public:gunit_main",
"//webrtc/api:libjingle_peerconnection_api",
],
)
cc_library(
name = "peer_id",
srcs = ["peer_id.cc"],
hdrs = ["peer_id.h"],
deps = [
"//core/internal/mediums:utils",
"//platform:types",
"//platform/api",
"//platform/port:string",
"//absl/strings",
],
)
cc_library(
name = "signaling_frames",
srcs = ["signaling_frames.cc"],
hdrs = ["signaling_frames.h"],
deps = [
":peer_id",
"//platform:types",
"//location/nearby/mediums/proto:web_rtc_signaling_frames_cc_proto",
"//webrtc/api:libjingle_peerconnection_api",
],
)
cc_test(
name = "peer_id_test",
srcs = ["peer_id_test.cc"],
deps = [
":peer_id",
"//platform:types",
"//platform/api",
"//platform/impl/g3", # buildcleaner: keep
"//testing/base/public:gunit_main",
"//absl/strings",
],
)
cc_test(
name = "signaling_frames_test",
srcs = ["signaling_frames_test.cc"],
deps = [
":peer_id",
":signaling_frames",
"//platform:types",
"//platform/impl/g3", # buildcleaner: keep
"//net/proto2/public:proto2",
"//testing/base/public:gunit_main",
"//webrtc/pc:peerconnection", # buildcleaner: keep
],
)
@@ -0,0 +1,55 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "core/internal/mediums/webrtc/peer_id.h"
#include <sstream>
#include "core/internal/mediums/utils.h"
#include "absl/strings/ascii.h"
#include "absl/strings/escaping.h"
namespace location {
namespace nearby {
namespace connections {
namespace mediums {
namespace {
constexpr int kPeerIdLength = 64;
std::string BytesToStringUppercase(ConstPtr<ByteArray> bytes) {
std::string hex_string(
absl::BytesToHexString(std::string(bytes->getData(), bytes->size())));
absl::AsciiStrToUpper(&hex_string);
return hex_string;
}
} // namespace
ConstPtr<PeerId> PeerId::FromRandom(Ptr<HashUtils> hash_utils) {
return FromSeed(Utils::generateRandomBytes(kPeerIdLength), hash_utils);
}
ConstPtr<PeerId> PeerId::FromSeed(ConstPtr<ByteArray> seed,
Ptr<HashUtils> hash_utils) {
ScopedPtr<ConstPtr<ByteArray>> full_hash(
Utils::sha256Hash(hash_utils, seed, kPeerIdLength));
ScopedPtr<ConstPtr<ByteArray>> hashedSeed(
MakeConstPtr(new ByteArray(full_hash->getData(), kPeerIdLength / 2)));
return MakeConstPtr(new PeerId(BytesToStringUppercase(hashedSeed.get())));
}
} // namespace mediums
} // namespace connections
} // namespace nearby
} // namespace location
@@ -0,0 +1,50 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_PEER_ID_H_
#define CORE_INTERNAL_MEDIUMS_WEBRTC_PEER_ID_H_
#include "platform/api/hash_utils.h"
#include "platform/byte_array.h"
#include "platform/port/string.h"
#include "platform/ptr.h"
namespace location {
namespace nearby {
namespace connections {
namespace mediums {
// PeerId is used as an identifier to exchange SDP messages to establish WebRTC
// p2p connection.
class PeerId {
public:
explicit PeerId(const string& id) : id_(id) {}
~PeerId() = default;
static ConstPtr<PeerId> FromRandom(Ptr<HashUtils> hash_utils);
static ConstPtr<PeerId> FromSeed(ConstPtr<ByteArray> seed,
Ptr<HashUtils> hash_utils);
const string& GetId() const { return id_; }
private:
const string id_;
};
} // namespace mediums
} // namespace connections
} // namespace nearby
} // namespace location
#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_PEER_ID_H_
@@ -0,0 +1,90 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "core/internal/mediums/webrtc/peer_id.h"
#include "platform/api/hash_utils.h"
#include "platform/byte_array.h"
#include "platform/ptr.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/strings/escaping.h"
namespace location {
namespace nearby {
namespace connections {
namespace mediums {
namespace {
class MockHashUtils : public HashUtils {
public:
MOCK_METHOD(ConstPtr<ByteArray>, md5, (const std::string& input), (override));
MOCK_METHOD(ConstPtr<ByteArray>, sha256, (const std::string& input),
(override));
};
} // namespace
TEST(PeerIdTest, GenerateRandomPeerId) {
// These are actual SHA-256 values for |seed| = "seed".
std::string hashed_output =
"19b25856e1c150ca834cffc8b59b23adbd0ec0389e58eb22b3b64768098d002b";
std::string expected_peer_id =
"19B25856E1C150CA834CFFC8B59B23ADBD0EC0389E58EB22B3B64768098D002B";
Ptr<testing::NiceMock<MockHashUtils>> mock_hash_utils(
MakePtr(new MockHashUtils()));
ON_CALL(*mock_hash_utils.get(), sha256(testing::_))
.WillByDefault(testing::Return(
MakeConstPtr(new ByteArray(absl::HexStringToBytes(hashed_output)))));
EXPECT_CALL(*mock_hash_utils.get(), sha256(testing::_));
ConstPtr<PeerId> peer_id = PeerId::FromRandom(mock_hash_utils);
ASSERT_EQ(64, peer_id->GetId().size());
ASSERT_EQ(expected_peer_id, peer_id->GetId());
}
TEST(PeerIdTest, GenerateFromSeed) {
// Values calculated by running actual SHA-256 hash on |seed|.
std::string seed = "sesdfed";
std::string hashed_output =
"19b25856e1c150ca834cffc8b59b23adbd0ec0389e58eb22b3b64768098d002b";
std::string expected_peer_id =
"19B25856E1C150CA834CFFC8B59B23ADBD0EC0389E58EB22B3B64768098D002B";
Ptr<testing::NiceMock<MockHashUtils>> mock_hash_utils(
MakePtr(new MockHashUtils()));
ON_CALL(*mock_hash_utils.get(), sha256(testing::Eq(seed)))
.WillByDefault(testing::Return(
MakeConstPtr(new ByteArray(absl::HexStringToBytes(hashed_output)))));
EXPECT_CALL(*mock_hash_utils.get(), sha256(testing::Eq(seed)));
ConstPtr<PeerId> peer_id =
PeerId::FromSeed(MakeConstPtr(new ByteArray(seed)), mock_hash_utils);
ASSERT_EQ(64, peer_id->GetId().size());
ASSERT_EQ(expected_peer_id, peer_id->GetId());
}
TEST(PeerIdTest, GetId) {
const std::string id = "this_is_a_test";
PeerId peer_id(id);
ASSERT_EQ(id, peer_id.GetId());
}
} // namespace mediums
} // namespace connections
} // namespace nearby
} // namespace location
@@ -0,0 +1,139 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "core/internal/mediums/webrtc/signaling_frames.h"
namespace location {
namespace nearby {
namespace connections {
namespace mediums {
namespace webrtc_frames {
using WebRtcSignalingFrame = location::nearby::mediums::WebRtcSignalingFrame;
namespace {
ConstPtr<ByteArray> FrameToByteArray(
const WebRtcSignalingFrame& signaling_frame) {
std::string message;
signaling_frame.SerializeToString(&message);
return MakeConstPtr(new ByteArray(message.c_str(), message.size()));
}
void SetSenderId(ConstPtr<PeerId> sender_id, WebRtcSignalingFrame& frame) {
frame.mutable_sender_id()->set_id(sender_id->GetId());
}
ConstPtr<webrtc::IceCandidateInterface> DecodeIceCandidate(
const location::nearby::mediums::IceCandidate& ice_candidate_proto) {
webrtc::SdpParseError error;
return ConstPtr<webrtc::IceCandidateInterface>(webrtc::CreateIceCandidate(
ice_candidate_proto.sdp_mid(), ice_candidate_proto.sdp_m_line_index(),
ice_candidate_proto.sdp(), &error));
}
} // namespace
ConstPtr<ByteArray> EncodeReadyForSignalingPoke(ConstPtr<PeerId> sender_id) {
WebRtcSignalingFrame signaling_frame;
signaling_frame.set_type(WebRtcSignalingFrame::READY_FOR_SIGNALING_POKE_TYPE);
SetSenderId(sender_id, signaling_frame);
signaling_frame.mutable_ready_for_signaling_poke();
return FrameToByteArray(std::move(signaling_frame));
}
ConstPtr<ByteArray> EncodeOffer(
ConstPtr<PeerId> sender_id,
const webrtc::SessionDescriptionInterface& offer) {
WebRtcSignalingFrame signaling_frame;
signaling_frame.set_type(WebRtcSignalingFrame::OFFER_TYPE);
SetSenderId(sender_id, signaling_frame);
std::string offer_str;
offer.ToString(&offer_str);
signaling_frame.mutable_offer()
->mutable_session_description()
->set_description(offer_str);
return FrameToByteArray(std::move(signaling_frame));
}
ConstPtr<ByteArray> EncodeAnswer(
ConstPtr<PeerId> sender_id,
const webrtc::SessionDescriptionInterface& answer) {
WebRtcSignalingFrame signaling_frame;
signaling_frame.set_type(WebRtcSignalingFrame::ANSWER_TYPE);
SetSenderId(sender_id, signaling_frame);
std::string answer_str;
answer.ToString(&answer_str);
signaling_frame.mutable_answer()
->mutable_session_description()
->set_description(answer_str);
return FrameToByteArray(std::move(signaling_frame));
}
ConstPtr<ByteArray> EncodeIceCandidates(
ConstPtr<PeerId> sender_id,
const std::vector<location::nearby::mediums::IceCandidate>&
ice_candidates) {
WebRtcSignalingFrame signaling_frame;
signaling_frame.set_type(WebRtcSignalingFrame::ICE_CANDIDATES_TYPE);
SetSenderId(sender_id, signaling_frame);
for (const auto& ice_candidate : ice_candidates) {
*signaling_frame.mutable_ice_candidates()->add_ice_candidates() =
ice_candidate;
}
return FrameToByteArray(std::move(signaling_frame));
}
Ptr<webrtc::SessionDescriptionInterface> DecodeOffer(
const WebRtcSignalingFrame& frame) {
return MakePtr(webrtc::CreateSessionDescription(
webrtc::SdpType::kOffer,
frame.offer().session_description().description())
.release());
}
Ptr<webrtc::SessionDescriptionInterface> DecodeAnswer(
const WebRtcSignalingFrame& frame) {
return MakePtr(webrtc::CreateSessionDescription(
webrtc::SdpType::kAnswer,
frame.answer().session_description().description())
.release());
}
std::vector<ConstPtr<webrtc::IceCandidateInterface>> DecodeIceCandidates(
const WebRtcSignalingFrame& frame) {
std::vector<ConstPtr<webrtc::IceCandidateInterface>> ice_candidates;
for (const auto& candidate : frame.ice_candidates().ice_candidates()) {
ice_candidates.push_back(DecodeIceCandidate(candidate));
}
return ice_candidates;
}
location::nearby::mediums::IceCandidate EncodeIceCandidate(
const webrtc::IceCandidateInterface& ice_candidate) {
std::string sdp;
ice_candidate.ToString(&sdp);
location::nearby::mediums::IceCandidate ice_candidate_proto;
ice_candidate_proto.set_sdp(sdp);
ice_candidate_proto.set_sdp_mid(ice_candidate.sdp_mid());
ice_candidate_proto.set_sdp_m_line_index(ice_candidate.sdp_mline_index());
return ice_candidate_proto;
}
} // namespace webrtc_frames
} // namespace mediums
} // namespace connections
} // namespace nearby
} // namespace location
@@ -0,0 +1,63 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_SIGNALING_FRAMES_H_
#define CORE_INTERNAL_MEDIUMS_WEBRTC_SIGNALING_FRAMES_H_
#include <vector>
#include "core/internal/mediums/webrtc/peer_id.h"
#include "platform/byte_array.h"
#include "platform/ptr.h"
#include "location/nearby/mediums/proto/web_rtc_signaling_frames.pb.h"
#include "webrtc/api/peer_connection_interface.h"
namespace location {
namespace nearby {
namespace connections {
namespace mediums {
namespace webrtc_frames {
ConstPtr<ByteArray> EncodeReadyForSignalingPoke(ConstPtr<PeerId> sender_id);
ConstPtr<ByteArray> EncodeOffer(
ConstPtr<PeerId> sender_id,
const webrtc::SessionDescriptionInterface& offer);
ConstPtr<ByteArray> EncodeAnswer(
ConstPtr<PeerId> sender_id,
const webrtc::SessionDescriptionInterface& answer);
ConstPtr<ByteArray> EncodeIceCandidates(
ConstPtr<PeerId> sender_id,
const std::vector<location::nearby::mediums::IceCandidate>& ice_candidates);
location::nearby::mediums::IceCandidate EncodeIceCandidate(
const webrtc::IceCandidateInterface& ice_candidate);
Ptr<webrtc::SessionDescriptionInterface> DecodeOffer(
const location::nearby::mediums::WebRtcSignalingFrame& frame);
Ptr<webrtc::SessionDescriptionInterface> DecodeAnswer(
const location::nearby::mediums::WebRtcSignalingFrame& frame);
std::vector<ConstPtr<webrtc::IceCandidateInterface>> DecodeIceCandidates(
const location::nearby::mediums::WebRtcSignalingFrame& frame);
} // namespace webrtc_frames
} // namespace mediums
} // namespace connections
} // namespace nearby
} // namespace location
#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_SIGNALING_FRAMES_H_
@@ -0,0 +1,198 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "core/internal/mediums/webrtc/signaling_frames.h"
#include <memory>
#include "core/internal/mediums/webrtc/peer_id.h"
#include "platform/ptr.h"
#include "net/proto2/public/text_format.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace location {
namespace nearby {
namespace connections {
namespace mediums {
namespace webrtc_frames {
namespace {
const char kSampleSdp[] =
"v=0\r\no=- 7859371131 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 "
"0\r\na=msid-semantic: WMS\r\n";
const char kIceCandidateSdp1[] =
"a=candidate:1 1 UDP 2130706431 10.0.1.1 8998 typ host";
const char kIceCandidateSdp2[] =
"a=candidate:2 1 UDP 1694498815 192.0.2.3 45664 typ srflx raddr";
const char kIceSdpMid[] = "data";
const int kIceSdpMLineIndex = 0;
const char kOfferProto[] = R"(
sender_id { id: "abc" }
type: OFFER_TYPE
offer {
session_description {
description: "v=0\r\no=- 7859371131 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS\r\n"
}
}
)";
const char kAnswerProto[] = R"(
sender_id { id: "abc" }
type: ANSWER_TYPE
answer {
session_description {
description: "v=0\r\no=- 7859371131 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS\r\n"
}
}
)";
const char kIceCandidatesProto[] = R"(
sender_id { id: "abc" }
type: ICE_CANDIDATES_TYPE
ice_candidates {
ice_candidates {
sdp: "candidate:1 1 udp 2130706431 10.0.1.1 8998 typ host generation 0"
sdp_mid: "data"
sdp_m_line_index: 0
}
ice_candidates {
sdp: "candidate:2 1 udp 1694498815 192.0.2.3 45664 typ srflx generation 0"
sdp_mid: "data"
sdp_m_line_index: 0
}
}
)";
} // namespace
TEST(SignalingFramesTest, SignalingPoke) {
ConstPtr<PeerId> sender_id(new PeerId("abc"));
ConstPtr<ByteArray> encoded_poke = EncodeReadyForSignalingPoke(sender_id);
location::nearby::mediums::WebRtcSignalingFrame frame;
frame.ParseFromString(
std::string(encoded_poke->getData(), encoded_poke->size()));
EXPECT_THAT(frame, testing::EqualsProto(R"(
sender_id { id: "abc" }
type: READY_FOR_SIGNALING_POKE_TYPE
ready_for_signaling_poke {}
)"));
}
TEST(SignalingFramesTest, EncodeValidOffer) {
ConstPtr<PeerId> sender_id(new PeerId("abc"));
std::unique_ptr<webrtc::SessionDescriptionInterface> offer =
webrtc::CreateSessionDescription(webrtc::SdpType::kOffer, kSampleSdp);
ConstPtr<ByteArray> encoded_offer = EncodeOffer(sender_id, *offer);
location::nearby::mediums::WebRtcSignalingFrame frame;
frame.ParseFromString(
std::string(encoded_offer->getData(), encoded_offer->size()));
EXPECT_THAT(frame, testing::EqualsProto(kOfferProto));
}
TEST(SignalingFramesTest, DecodeValidOffer) {
location::nearby::mediums::WebRtcSignalingFrame frame;
proto2::TextFormat::ParseFromString(kOfferProto, &frame);
Ptr<webrtc::SessionDescriptionInterface> decoded_offer = DecodeOffer(frame);
EXPECT_EQ(webrtc::SdpType::kOffer, decoded_offer->GetType());
std::string description;
decoded_offer->ToString(&description);
EXPECT_EQ(kSampleSdp, description);
}
TEST(SignalingFramesTest, EncodeValidAnswer) {
ConstPtr<PeerId> sender_id(new PeerId("abc"));
std::unique_ptr<webrtc::SessionDescriptionInterface> answer =
webrtc::CreateSessionDescription(webrtc::SdpType::kAnswer, kSampleSdp);
ConstPtr<ByteArray> encoded_answer = EncodeAnswer(sender_id, *answer);
location::nearby::mediums::WebRtcSignalingFrame frame;
frame.ParseFromString(
std::string(encoded_answer->getData(), encoded_answer->size()));
EXPECT_THAT(frame, testing::EqualsProto(kAnswerProto));
}
TEST(SignalingFramesTest, DecodeValidAnswer) {
location::nearby::mediums::WebRtcSignalingFrame frame;
proto2::TextFormat::ParseFromString(kAnswerProto, &frame);
Ptr<webrtc::SessionDescriptionInterface> decoded_answer = DecodeAnswer(frame);
EXPECT_EQ(webrtc::SdpType::kAnswer, decoded_answer->GetType());
std::string description;
decoded_answer->ToString(&description);
EXPECT_EQ(kSampleSdp, description);
}
TEST(SignalingFramesTest, EncodeValidIceCandidates) {
ConstPtr<PeerId> sender_id(new PeerId("abc"));
webrtc::SdpParseError error;
std::vector<ConstPtr<webrtc::IceCandidateInterface>> ice_candidates;
ice_candidates.emplace_back(webrtc::CreateIceCandidate(
kIceSdpMid, kIceSdpMLineIndex, kIceCandidateSdp1, &error));
ice_candidates.emplace_back(webrtc::CreateIceCandidate(
kIceSdpMid, kIceSdpMLineIndex, kIceCandidateSdp2, &error));
std::vector<location::nearby::mediums::IceCandidate> encoded_candidates_vec;
for (const auto& ice_candidate : ice_candidates) {
encoded_candidates_vec.push_back(EncodeIceCandidate(*ice_candidate.get()));
}
ConstPtr<ByteArray> encoded_candidates =
EncodeIceCandidates(sender_id, encoded_candidates_vec);
location::nearby::mediums::WebRtcSignalingFrame frame;
frame.ParseFromString(
std::string(encoded_candidates->getData(), encoded_candidates->size()));
EXPECT_THAT(frame, testing::EqualsProto(kIceCandidatesProto));
}
TEST(SignalingFramesTest, DecodeValidIceCandidates) {
webrtc::SdpParseError error;
std::vector<ConstPtr<webrtc::IceCandidateInterface>> ice_candidates;
ice_candidates.emplace_back(webrtc::CreateIceCandidate(
kIceSdpMid, kIceSdpMLineIndex, kIceCandidateSdp1, &error));
ice_candidates.emplace_back(webrtc::CreateIceCandidate(
kIceSdpMid, kIceSdpMLineIndex, kIceCandidateSdp2, &error));
std::vector<location::nearby::mediums::IceCandidate> encoded_candidates_vec;
location::nearby::mediums::WebRtcSignalingFrame frame;
proto2::TextFormat::ParseFromString(kIceCandidatesProto, &frame);
std::vector<ConstPtr<webrtc::IceCandidateInterface>> decoded_candidates =
DecodeIceCandidates(frame);
ASSERT_EQ(2u, decoded_candidates.size());
for (int i = 0; i < static_cast<int>(decoded_candidates.size()); i++) {
EXPECT_TRUE(ice_candidates[i]->candidate().IsEquivalent(
decoded_candidates[i]->candidate()));
EXPECT_EQ(ice_candidates[i]->sdp_mid(), decoded_candidates[i]->sdp_mid());
EXPECT_EQ(ice_candidates[i]->sdp_mline_index(),
decoded_candidates[i]->sdp_mline_index());
}
}
} // namespace webrtc_frames
} // namespace mediums
} // namespace connections
} // namespace nearby
} // namespace location
@@ -0,0 +1,153 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "core/internal/mediums/webrtc/webrtc_socket.h"
#include "platform/synchronized.h"
namespace location {
namespace nearby {
namespace connections {
namespace mediums {
// OutputStreamImpl
template <typename Platform>
Exception::Value WebRtcSocket<Platform>::OutputStreamImpl::write(
ConstPtr<ByteArray> data) {
ScopedPtr<ConstPtr<ByteArray>> scoped_data(data);
if (scoped_data->size() > kMaxDataSize) {
NEARBY_LOG(WARNING, "Sending data larger than 1MB");
return Exception::IO;
}
socket_->BlockUntilSufficientSpaceInBuffer(scoped_data->size());
if (socket_->IsClosed()) {
NEARBY_LOG(WARNING, "Tried sending message while socket is closed");
return Exception::IO;
}
if (!socket_->SendMessage(scoped_data.release())) {
return Exception::IO;
}
return Exception::NONE;
}
template <typename Platform>
Exception::Value WebRtcSocket<Platform>::OutputStreamImpl::flush() {
// Java implementation is empty.
return Exception::NONE;
}
template <typename Platform>
Exception::Value WebRtcSocket<Platform>::OutputStreamImpl::close() {
socket_->close();
return Exception::NONE;
}
// WebRtcSocket
template <typename Platform>
WebRtcSocket<Platform>::WebRtcSocket(
const string& name,
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel)
: name_(name),
data_channel_(std::move(data_channel)),
pipe_(MakeRefCountedPtr(new Pipe())),
incoming_data_piped_input_stream_(Pipe::createInputStream(pipe_)),
incoming_data_piped_output_stream_(Pipe::createOutputStream(pipe_)),
output_stream_(MakePtr(new OutputStreamImpl(this))),
closed_(Platform::createAtomicBoolean(false)),
backpressure_lock_(Platform::createLock()),
buffer_variable_(
Platform::createConditionVariable(backpressure_lock_.get())) {}
template <typename Platform>
Ptr<InputStream> WebRtcSocket<Platform>::getInputStream() {
return incoming_data_piped_input_stream_.get();
}
template <typename Platform>
Ptr<OutputStream> WebRtcSocket<Platform>::getOutputStream() {
return output_stream_.get();
}
template <typename Platform>
void WebRtcSocket<Platform>::close() {
if (IsClosed()) return;
closed_->set(true);
incoming_data_piped_output_stream_->close();
incoming_data_piped_input_stream_->close();
data_channel_->Close();
WakeUpWriter();
if (!socket_closed_listener_.isNull()) {
socket_closed_listener_->OnSocketClosed();
}
}
template <typename Platform>
void WebRtcSocket<Platform>::NotifyDataChannelMsgReceived(
ConstPtr<ByteArray> message) {
Exception::Value exception =
incoming_data_piped_output_stream_->write(message);
if (exception != Exception::NONE) close();
exception = incoming_data_piped_output_stream_->flush();
if (exception != Exception::NONE) close();
}
template <typename Platform>
void WebRtcSocket<Platform>::NotifyDataChannelBufferedAmountChanged() {
WakeUpWriter();
}
template <typename Platform>
bool WebRtcSocket<Platform>::SendMessage(ConstPtr<ByteArray> data) {
ScopedPtr<ConstPtr<ByteArray>> scoped_data(data);
return data_channel_->Send(webrtc::DataBuffer(
std::string(scoped_data->getData(), scoped_data->size())));
}
template <typename Platform>
bool WebRtcSocket<Platform>::IsClosed() {
return closed_->get();
}
template <typename Platform>
void WebRtcSocket<Platform>::WakeUpWriter() {
Synchronized s(backpressure_lock_.get());
buffer_variable_->notify();
}
template <typename Platform>
void WebRtcSocket<Platform>::SetOnSocketClosedListener(
Ptr<SocketClosedListener> listener) {
socket_closed_listener_ = listener;
}
template <typename Platform>
void WebRtcSocket<Platform>::BlockUntilSufficientSpaceInBuffer(int length) {
Synchronized s(backpressure_lock_.get());
while (!IsClosed() &&
(data_channel_->buffered_amount() + length > kMaxDataSize)) {
// TODO(himanshujaju): Add wait with timeout.
buffer_variable_->wait();
}
}
} // namespace mediums
} // namespace connections
} // namespace nearby
} // namespace location
@@ -0,0 +1,118 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_H_
#define CORE_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_H_
#include "platform/api/atomic_boolean.h"
#include "platform/api/input_stream.h"
#include "platform/api/output_stream.h"
#include "platform/api/socket.h"
#include "platform/pipe.h"
#include "webrtc/api/data_channel_interface.h"
namespace location {
namespace nearby {
namespace connections {
namespace mediums {
// Maximum data size: 1 MB
constexpr int kMaxDataSize = 1 * 1024 * 1024;
// Defines the Socket implementation specific to WebRTC, which uses the WebRTC
// data channel to send and receive messages.
//
// Messages are buffered here to prevent the data channel from overflowing,
// which could lead to data loss.
template <typename Platform>
class WebRtcSocket : public Socket {
public:
WebRtcSocket(const string& name,
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel);
~WebRtcSocket() override = default;
WebRtcSocket(const WebRtcSocket& other) = delete;
WebRtcSocket& operator=(const WebRtcSocket& other) = delete;
// Overrides for location::nearby::Socket:
Ptr<InputStream> getInputStream() override;
Ptr<OutputStream> getOutputStream() override;
void close() override;
// Callback from WebRTC data channel when new message has been received from
// the remote.
void NotifyDataChannelMsgReceived(ConstPtr<ByteArray> message);
// Callback from WebRTC data channel that the buffered data amount has
// changed.
void NotifyDataChannelBufferedAmountChanged();
// Listener class the gets called when the socket is closed.
class SocketClosedListener {
public:
virtual ~SocketClosedListener() = default;
virtual void OnSocketClosed() = 0;
};
void SetOnSocketClosedListener(Ptr<SocketClosedListener> listener);
private:
class OutputStreamImpl : public OutputStream {
public:
explicit OutputStreamImpl(WebRtcSocket<Platform>* const socket)
: socket_(socket) {}
~OutputStreamImpl() override = default;
OutputStreamImpl(const OutputStreamImpl& other) = delete;
OutputStreamImpl& operator=(const OutputStreamImpl& other) = delete;
// OutputStream:
Exception::Value write(ConstPtr<ByteArray> data) override;
Exception::Value flush() override;
Exception::Value close() override;
private:
// |this| OutputStreamImpl is owned by |socket_|.
WebRtcSocket<Platform>* const socket_;
};
void WakeUpWriter();
bool IsClosed();
bool SendMessage(ConstPtr<ByteArray> data);
void BlockUntilSufficientSpaceInBuffer(int length);
string name_;
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel_;
Ptr<Pipe> pipe_;
ScopedPtr<Ptr<InputStream>> incoming_data_piped_input_stream_;
ScopedPtr<Ptr<OutputStream>> incoming_data_piped_output_stream_;
ScopedPtr<Ptr<OutputStream>> output_stream_;
ScopedPtr<Ptr<AtomicBoolean>> closed_;
Ptr<SocketClosedListener> socket_closed_listener_;
ScopedPtr<Ptr<Lock>> backpressure_lock_;
ScopedPtr<Ptr<ConditionVariable>> buffer_variable_;
};
} // namespace mediums
} // namespace connections
} // namespace nearby
} // namespace location
#include "core/internal/mediums/webrtc/webrtc_socket.cc"
#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_H_
@@ -0,0 +1,169 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "core/internal/mediums/webrtc/webrtc_socket.h"
#include "platform/api/platform.h"
#include "platform/byte_array.h"
#include "platform/ptr.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "webrtc/api/data_channel_interface.h"
namespace location {
namespace nearby {
namespace connections {
namespace mediums {
namespace {
using TestPlatform = platform::ImplementationPlatform;
const char kSocketName[] = "TestSocket";
class MockDataChannel
: public rtc::RefCountedObject<webrtc::DataChannelInterface> {
public:
MOCK_METHOD(void, RegisterObserver, (webrtc::DataChannelObserver*));
MOCK_METHOD(void, UnregisterObserver, ());
MOCK_METHOD(std::string, label, (), (const));
MOCK_METHOD(bool, reliable, (), (const));
MOCK_METHOD(int, id, (), (const));
MOCK_METHOD(DataState, state, (), (const));
MOCK_METHOD(uint32_t, messages_sent, (), (const));
MOCK_METHOD(uint64_t, bytes_sent, (), (const));
MOCK_METHOD(uint32_t, messages_received, (), (const));
MOCK_METHOD(uint64_t, bytes_received, (), (const));
MOCK_METHOD(uint64_t, buffered_amount, (), (const));
MOCK_METHOD(void, Close, ());
MOCK_METHOD(bool, Send, (const webrtc::DataBuffer&));
};
} // namespace
class MockSocketClosedListener
: public WebRtcSocket<TestPlatform>::SocketClosedListener {
public:
MOCK_METHOD(void, OnSocketClosed, ());
};
TEST(WebRtcSocketTest, ReadFromSocket) {
ConstPtr<ByteArray> kMessage = MakeConstPtr(new ByteArray("Message"));
rtc::scoped_refptr<MockDataChannel> mock_data_channel = new MockDataChannel();
WebRtcSocket<TestPlatform> webrtc_socket(kSocketName, mock_data_channel);
webrtc_socket.NotifyDataChannelMsgReceived(kMessage);
ExceptionOr<ConstPtr<ByteArray>> result =
webrtc_socket.getInputStream()->read();
EXPECT_TRUE(result.ok());
EXPECT_EQ(result.result(), kMessage);
}
TEST(WebRtcSocketTest, ReadMultipleMessages) {
rtc::scoped_refptr<MockDataChannel> mock_data_channel = new MockDataChannel();
WebRtcSocket<TestPlatform> webrtc_socket(kSocketName, mock_data_channel);
webrtc_socket.NotifyDataChannelMsgReceived(MakeConstPtr(new ByteArray("Me")));
webrtc_socket.NotifyDataChannelMsgReceived(
MakeConstPtr(new ByteArray("ssa")));
webrtc_socket.NotifyDataChannelMsgReceived(MakeConstPtr(new ByteArray("ge")));
ExceptionOr<ConstPtr<ByteArray>> result;
// This behaviour is different from the Java code
result = webrtc_socket.getInputStream()->read();
EXPECT_TRUE(result.ok());
EXPECT_EQ(result.result()->asString(), "Me");
result = webrtc_socket.getInputStream()->read();
EXPECT_TRUE(result.ok());
EXPECT_EQ(result.result()->asString(), "ssa");
result = webrtc_socket.getInputStream()->read();
EXPECT_TRUE(result.ok());
EXPECT_EQ(result.result()->asString(), "ge");
}
TEST(WebRtcSocketTest, WriteToSocket) {
ConstPtr<ByteArray> kMessage = MakeConstPtr(new ByteArray("Message"));
rtc::scoped_refptr<MockDataChannel> mock_data_channel = new MockDataChannel();
WebRtcSocket<TestPlatform> webrtc_socket(kSocketName, mock_data_channel);
EXPECT_CALL(*mock_data_channel, Send(testing::_))
.WillRepeatedly(testing::Return(true));
EXPECT_EQ(webrtc_socket.getOutputStream()->write(kMessage), Exception::NONE);
}
TEST(WebRtcSocketTest, SendDataBiggerThanMax) {
ConstPtr<ByteArray> kMessage = MakeConstPtr(new ByteArray(kMaxDataSize + 1));
rtc::scoped_refptr<MockDataChannel> mock_data_channel = new MockDataChannel();
WebRtcSocket<TestPlatform> webrtc_socket(kSocketName, mock_data_channel);
EXPECT_CALL(*mock_data_channel, Send(testing::_)).Times(0);
EXPECT_EQ(webrtc_socket.getOutputStream()->write(kMessage), Exception::IO);
}
TEST(WebRtcSocketTest, WriteToDataChannelFails) {
ConstPtr<ByteArray> kMessage = MakeConstPtr(new ByteArray("Message"));
rtc::scoped_refptr<MockDataChannel> mock_data_channel = new MockDataChannel();
WebRtcSocket<TestPlatform> webrtc_socket(kSocketName, mock_data_channel);
ON_CALL(*mock_data_channel, Send(testing::_))
.WillByDefault(testing::Return(false));
EXPECT_EQ(webrtc_socket.getOutputStream()->write(kMessage), Exception::IO);
}
TEST(WebRtcSocketTest, Close) {
rtc::scoped_refptr<MockDataChannel> mock_data_channel = new MockDataChannel();
ScopedPtr<Ptr<MockSocketClosedListener>> mock_listener(
MakePtr(new MockSocketClosedListener()));
WebRtcSocket<TestPlatform> webrtc_socket(kSocketName, mock_data_channel);
webrtc_socket.SetOnSocketClosedListener(mock_listener.get());
EXPECT_CALL(*mock_listener, OnSocketClosed());
EXPECT_CALL(*mock_data_channel, Close());
webrtc_socket.close();
}
TEST(WebRtcSocketTest, WriteOnClosedChannel) {
ConstPtr<ByteArray> kMessage = MakeConstPtr(new ByteArray("Message"));
rtc::scoped_refptr<MockDataChannel> mock_data_channel = new MockDataChannel();
WebRtcSocket<TestPlatform> webrtc_socket(kSocketName, mock_data_channel);
webrtc_socket.close();
EXPECT_CALL(*mock_data_channel, Send(testing::_)).Times(0);
EXPECT_EQ(webrtc_socket.getOutputStream()->write(kMessage), Exception::IO);
}
TEST(WebRtcSocketTest, ReadFromClosedChannel) {
ConstPtr<ByteArray> kMessage = MakeConstPtr(new ByteArray("Message"));
rtc::scoped_refptr<MockDataChannel> mock_data_channel = new MockDataChannel();
WebRtcSocket<TestPlatform> webrtc_socket(kSocketName, mock_data_channel);
ON_CALL(*mock_data_channel, Send(testing::_))
.WillByDefault(testing::Return(true));
webrtc_socket.getOutputStream()->write(kMessage);
webrtc_socket.close();
EXPECT_EQ(webrtc_socket.getInputStream()->read().exception(), Exception::IO);
}
} // namespace mediums
} // namespace connections
} // namespace nearby
} // namespace location
+227
View File
@@ -0,0 +1,227 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "core/internal/mediums/wifi_lan.h"
#include "platform/synchronized.h"
namespace location {
namespace nearby {
namespace connections {
namespace mediums {
template <typename Platform>
WifiLan<Platform>::WifiLan()
: lock_(Platform::createLock()),
wifi_lan_medium_(Platform::createWifiLanMedium()) {}
template <typename Platform>
bool WifiLan<Platform>::IsAvailable() {
Synchronized s(lock_.get());
return !wifi_lan_medium_.isNull();
}
template <typename Platform>
bool WifiLan<Platform>::StartAdvertising(
absl::string_view service_id,
absl::string_view wifi_lan_service_info_name) {
Synchronized s(lock_.get());
if (!IsAvailable()) {
return false;
}
// TODO(b/149806065): Implements platform wifi-lan medium.
// wifi_lan_medium_->StartAdvertising(service_id,
// wifi_lan_service_info_name));
advertising_info_.service_id.assign(service_id.data());
return false;
}
template <typename Platform>
void WifiLan<Platform>::StopAdvertising(absl::string_view service_id) {
Synchronized s(lock_.get());
if (!IsAdvertising()) {
return;
}
// TODO(b/149806065): Implements platform wifi-lan medium.
// wifi_lan_medium_->StopAdvertising(advertising_info_.service_id);
// Reset our bundle of advertising state to mark that we're no longer
// advertising.
advertising_info_.service_id.clear();
}
template <typename Platform>
bool WifiLan<Platform>::IsAdvertising() {
Synchronized s(lock_.get());
return !advertising_info_.service_id.empty();
}
template <typename Platform>
bool WifiLan<Platform>::StartDiscovery(
absl::string_view service_id,
Ptr<DiscoveredServiceCallback> discovered_service_callback) {
Synchronized s(lock_.get());
if (discovered_service_callback.isNull() || service_id.empty()) {
// TODO(b/149806065): logger.atSevere().log("Refusing to start WifiLan
// discovering because a null parameter was passed in.");
return false;
}
if (IsDiscovering(service_id)) {
// TODO(b/149806065): logger.atSevere().log("Refusing to start WifiLan
// discovering because we are already discovering.");
return false;
}
if (!IsAvailable()) {
// TODO(b/149806065): logger.atSevere().log("Can't start WifiLan discovering
// because WifiLan isn't available.");
return false;
}
// Avoid leaks.
ScopedPtr<Ptr<DiscoveredServiceCallbackBridge>>
scoped_discovered_service_callback_bridge(
new DiscoveredServiceCallbackBridge(discovered_service_callback));
// TODO(b/149806065): Implements platform wifi-lan medium.
// A possible implementation is:
// wifi_lan_medium_->StartDiscovery(
// service_id, Ptr<DiscoveredServiceCallbackBridge>(
// discovered_service_callback_bridge.release()));
discovering_info_.service_id.assign(service_id.data());
return false;
}
template <typename Platform>
void WifiLan<Platform>::StopDiscovery(absl::string_view service_id) {
Synchronized s(lock_.get());
if (!IsDiscovering(service_id)) {
// TODO(b/149806065): logger.atDebug().log("Can't turn off WifiLan
// discovering because we never started discovering.");
return;
}
// TODO(b/149806065): Implements platform wifi-lan medium.
// wifi_lan_medium_->StopDiscovery(discovering_info_.service_id);
// Reset our bundle of scanning state to mark that we're no longer scanning.
discovering_info_.service_id.clear();
}
template <typename Platform>
bool WifiLan<Platform>::IsDiscovering(absl::string_view service_id) {
Synchronized s(lock_.get());
return !discovering_info_.service_id.empty();
}
template <typename Platform>
bool WifiLan<Platform>::StartAcceptingConnections(
absl::string_view service_id,
Ptr<AcceptedConnectionCallback> accepted_connection_callback) {
Synchronized s(lock_.get());
if (accepted_connection_callback.isNull() || service_id.empty()) {
// TODO(b/149806065): logger.atSevere().log("Refusing to start accepting
// WifiLan connections because a null parameter was passed in.");
return false;
}
if (IsAcceptingConnections(service_id)) {
// TODO(b/149806065): logger.atSevere().log("Refusing to start accepting
// WifiLan connections for %s because another WifiLan service socket is
// already in-progress.", service_id);
return false;
}
if (!IsAvailable()) {
// TODO(b/149806065): logger.atSevere().log("Can't start accepting WifiLan
// connections for %s because WifiLan isn't available.", serviceId);
return false;
}
ScopedPtr<Ptr<WifiLanAcceptedConnectionCallback>>
scoped_wifi_lan_accepted_connection_callback(
new WifiLanAcceptedConnectionCallback(
accepted_connection_callback));
// TODO(b/149806065): Implements platform wifi-lan medium.
// A possible implementation is:
// wifi_lan_medium_->StartAcceptingConnections(
// service_id, Ptr<WifiLanAcceptedConnectionCallback>(
// wifi_lan_accepted_connection_callback.release()));
accepting_connections_info_.service_id.assign(service_id.data());
return false;
}
template <typename Platform>
void WifiLan<Platform>::StopAcceptingConnections(absl::string_view service_id) {
Synchronized s(lock_.get());
if (!IsAcceptingConnections(service_id)) {
// TODO(b/149806065): logger.atDebug().log("Can't stop accepting WifiLan
// connections because it was never started.");
return;
}
// TODO(b/149806065): Implements platform wifi-lan medium.);
// A possible implementation is:
// wifi_lan_medium_->StopAcceptingConnections(
// accepting_connections_info_.service_id);
// Reset our bundle of accepting connections state to mark that we're no
// longer accepting connections.
accepting_connections_info_.service_id.clear();
}
template <typename Platform>
bool WifiLan<Platform>::IsAcceptingConnections(absl::string_view service_id) {
Synchronized s(lock_.get());
return !accepting_connections_info_.service_id.empty();
}
template <typename Platform>
Ptr<WifiLanSocket> WifiLan<Platform>::Connect(
Ptr<WifiLanService> wifi_lan_service, absl::string_view service_id) {
Synchronized s(lock_.get());
if (wifi_lan_service.isNull() || service_id.empty()) {
return Ptr<WifiLanSocket>();
}
if (!IsAvailable()) {
return Ptr<WifiLanSocket>();
}
// TODO(b/149806065): Implements platform wifi-lan medium.
// A possible implementation is:
// return wifi_lan_medium_->Connect(wifi_lan_service, service_id);
return Ptr<WifiLanSocket>();
}
} // namespace mediums
} // namespace connections
} // namespace nearby
} // namespace location
+174
View File
@@ -0,0 +1,174 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CORE_INTERNAL_MEDIUMS_WIFI_LAN_H_
#define CORE_INTERNAL_MEDIUMS_WIFI_LAN_H_
#include <cstdint>
#include "platform/api/lock.h"
#include "platform/api/wifi_lan.h"
#include "platform/byte_array.h"
#include "platform/port/string.h"
#include "platform/ptr.h"
#include "absl/strings/string_view.h"
namespace location {
namespace nearby {
namespace connections {
namespace mediums {
class DiscoveredServiceCallback {
public:
virtual ~DiscoveredServiceCallback() = default;
virtual void OnServiceDiscovered(Ptr<WifiLanService> wifi_lan_service) = 0;
virtual void OnServiceLost(Ptr<WifiLanService> wifi_lan_service) = 0;
};
template <typename Platform>
class WifiLan {
public:
WifiLan();
virtual ~WifiLan() = default;
bool IsAvailable();
bool StartAdvertising(absl::string_view service_id,
absl::string_view wifi_lan_service_info_name);
void StopAdvertising(absl::string_view service_id);
bool IsAdvertising();
bool StartDiscovery(
absl::string_view service_id,
Ptr<DiscoveredServiceCallback> discovered_service_callback);
void StopDiscovery(absl::string_view service_id);
bool IsDiscovering(absl::string_view service_id);
class AcceptedConnectionCallback {
public:
virtual ~AcceptedConnectionCallback() = default;
virtual void OnConnectionAccepted(Ptr<WifiLanSocket> socket,
absl::string_view service_id) = 0;
};
bool StartAcceptingConnections(
absl::string_view service_id,
Ptr<AcceptedConnectionCallback> accepted_connection_callback);
void StopAcceptingConnections(absl::string_view service_id);
bool IsAcceptingConnections(absl::string_view service_id);
Ptr<WifiLanSocket> Connect(Ptr<WifiLanService> wifi_lan_service,
absl::string_view service_id);
private:
class DiscoveredServiceCallbackBridge
: public WifiLanMedium::DiscoveredServiceCallback {
public:
explicit DiscoveredServiceCallbackBridge(
Ptr<mediums::DiscoveredServiceCallback> discovered_service_callback)
: discovered_service_callback_(discovered_service_callback) {}
~DiscoveredServiceCallbackBridge() override = default;
void OnServiceDiscovered(Ptr<WifiLanService> wifi_lan_service) override {
discovered_service_callback_->OnServiceDiscovered(wifi_lan_service);
}
void OnServiceLost(Ptr<WifiLanService> wifi_lan_service) override {
discovered_service_callback_->OnServiceLost(wifi_lan_service);
}
private:
ScopedPtr<Ptr<mediums::DiscoveredServiceCallback>>
discovered_service_callback_;
};
class WifiLanAcceptedConnectionCallback
: public WifiLanMedium::AcceptedConnectionCallback {
public:
explicit WifiLanAcceptedConnectionCallback(
Ptr<WifiLan::AcceptedConnectionCallback> accepted_connection_callback)
: accepted_connection_callback_(accepted_connection_callback) {}
~WifiLanAcceptedConnectionCallback() override = default;
void OnConnectionAccepted(Ptr<WifiLanSocket> wifi_lan_socket,
absl::string_view service_id) override {
accepted_connection_callback_->OnConnectionAccepted(wifi_lan_socket,
service_id);
}
private:
ScopedPtr<Ptr<WifiLan::AcceptedConnectionCallback>>
accepted_connection_callback_;
};
struct DiscoveringInfo {
DiscoveringInfo() = default;
explicit DiscoveringInfo(absl::string_view service_id)
: service_id(service_id) {}
~DiscoveringInfo() = default;
string service_id;
};
struct AdvertisingInfo {
AdvertisingInfo() = default;
explicit AdvertisingInfo(absl::string_view service_id)
: service_id(service_id) {}
~AdvertisingInfo() = default;
string service_id;
};
struct AcceptingConnectionsInfo {
AcceptingConnectionsInfo() = default;
explicit AcceptingConnectionsInfo(absl::string_view service_id)
: service_id(service_id) {}
~AcceptingConnectionsInfo() = default;
string service_id;
};
// ------------ GENERAL ------------
ScopedPtr<Ptr<Lock>> lock_;
// ---------- CORE WIFILAN------------
// The underlying, per-platform implementation.
ScopedPtr<Ptr<WifiLanMedium>> wifi_lan_medium_;
// ------------ DISCOVERY ------------
// discovering_info_ is not scoped because it's nullable.
DiscoveringInfo discovering_info_;
// ------------ ADVERTISING ------------
// A bundle of state required to start/stop WifiLan service publishing.
AdvertisingInfo advertising_info_;
// A bundle of state required to start/stop accepting WifiLan service
/// connections.
AcceptingConnectionsInfo accepting_connections_info_;
};
} // namespace mediums
} // namespace connections
} // namespace nearby
} // namespace location
#include "core/internal/mediums/wifi_lan.cc"
#endif // CORE_INTERNAL_MEDIUMS_WIFI_LAN_H_