mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 07:36:10 -04:00
ios: nearbyConnections: Move source to //third_party.
PiperOrigin-RevId: 408046875
This commit is contained in:
committed by
Copybara-Service
parent
8c2dd35eac
commit
fb0337ebfa
@@ -0,0 +1,93 @@
|
||||
# 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.
|
||||
licenses(["notice"])
|
||||
|
||||
package(default_visibility = ["//platform/impl/ios:__subpackages__"])
|
||||
|
||||
objc_library(
|
||||
name = "Platform",
|
||||
srcs = [
|
||||
"crypto.mm",
|
||||
"input_file.mm",
|
||||
"log_message.mm",
|
||||
"multi_thread_executor.mm",
|
||||
"scheduled_executor.mm",
|
||||
"utils.mm",
|
||||
"wifi_lan.mm",
|
||||
],
|
||||
hdrs = [
|
||||
"input_file.h",
|
||||
"log_message.h",
|
||||
"multi_thread_executor.h",
|
||||
"scheduled_executor.h",
|
||||
"single_thread_executor.h",
|
||||
"utils.h",
|
||||
"wifi_lan.h",
|
||||
],
|
||||
sdk_frameworks = [
|
||||
"CoreBluetooth",
|
||||
"CoreFoundation",
|
||||
],
|
||||
deps = [
|
||||
":Platform_cc",
|
||||
"//platform/api:platform",
|
||||
"//platform/api:types",
|
||||
"//platform/impl/ios/Source/Mediums",
|
||||
"//platform/impl/ios/Source/Shared",
|
||||
"//platform/impl/shared:file",
|
||||
"//third_party/objective_c/google_toolbox_for_mac:GTM_Logger",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "Platform_cc",
|
||||
srcs = [
|
||||
"condition_variable.cc",
|
||||
"count_down_latch.cc",
|
||||
"system_clock.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"atomic_boolean.h",
|
||||
"atomic_uint32.h",
|
||||
"condition_variable.h",
|
||||
"count_down_latch.h",
|
||||
"mutex.h",
|
||||
],
|
||||
deps = [
|
||||
"//absl/strings:str_format",
|
||||
"//absl/synchronization",
|
||||
"//absl/time",
|
||||
"//platform/api:platform",
|
||||
"//platform/api:types",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "Platform_cc_test",
|
||||
srcs = [
|
||||
"atomic_boolean_test.cc",
|
||||
"atomic_uint32_test.cc",
|
||||
"condition_variable_test.cc",
|
||||
"count_down_latch_test.cc",
|
||||
"mutex_test.cc",
|
||||
],
|
||||
shard_count = 16,
|
||||
deps = [
|
||||
":Platform_cc",
|
||||
"//testing/base/public:gunit_main",
|
||||
"//absl/synchronization",
|
||||
"//absl/time",
|
||||
"//thread/fiber",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,46 @@
|
||||
// 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 PLATFORM_IMPL_IOS_ATOMIC_BOOLEAN_H_
|
||||
#define PLATFORM_IMPL_IOS_ATOMIC_BOOLEAN_H_
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "platform/api/atomic_boolean.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
|
||||
// Concrete AtomicBoolean implementation.
|
||||
class AtomicBoolean : public api::AtomicBoolean {
|
||||
public:
|
||||
explicit AtomicBoolean(bool initial_value) : value_(initial_value) {}
|
||||
~AtomicBoolean() override = default;
|
||||
|
||||
AtomicBoolean(const AtomicBoolean&) = delete;
|
||||
AtomicBoolean& operator=(const AtomicBoolean&) = delete;
|
||||
|
||||
bool Get() const override { return value_.load(); }
|
||||
bool Set(bool value) override { return value_.exchange(value); }
|
||||
|
||||
private:
|
||||
std::atomic_bool value_;
|
||||
};
|
||||
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_IMPL_IOS_ATOMIC_BOOLEAN_H_
|
||||
@@ -0,0 +1,78 @@
|
||||
// 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 "platform/impl/ios/Source/Platform/atomic_boolean.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "thread/fiber/fiber.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
namespace {
|
||||
|
||||
TEST(AtomicBooleanTest, SetOnSameThread) {
|
||||
AtomicBoolean atomic_boolean_{false};
|
||||
|
||||
EXPECT_EQ(false, atomic_boolean_.Get());
|
||||
|
||||
atomic_boolean_.Set(true);
|
||||
EXPECT_EQ(true, atomic_boolean_.Get());
|
||||
}
|
||||
|
||||
TEST(AtomicBooleanTest, MultipleSetGetOnSameThread) {
|
||||
AtomicBoolean atomic_boolean_{false};
|
||||
|
||||
EXPECT_EQ(false, atomic_boolean_.Get());
|
||||
|
||||
atomic_boolean_.Set(true);
|
||||
EXPECT_EQ(true, atomic_boolean_.Get());
|
||||
|
||||
atomic_boolean_.Set(true);
|
||||
EXPECT_EQ(true, atomic_boolean_.Get());
|
||||
|
||||
atomic_boolean_.Set(false);
|
||||
EXPECT_EQ(false, atomic_boolean_.Get());
|
||||
|
||||
atomic_boolean_.Set(true);
|
||||
EXPECT_EQ(true, atomic_boolean_.Get());
|
||||
}
|
||||
|
||||
TEST(AtomicBooleanTest, SetOnNewThread) {
|
||||
AtomicBoolean atomic_boolean_{false};
|
||||
|
||||
EXPECT_EQ(false, atomic_boolean_.Get());
|
||||
|
||||
thread::Fiber f([&] { atomic_boolean_.Set(true); });
|
||||
f.Join();
|
||||
|
||||
EXPECT_EQ(true, atomic_boolean_.Get());
|
||||
}
|
||||
|
||||
TEST(AtomicBooleanTest, GetOnNewThread) {
|
||||
AtomicBoolean atomic_boolean_{false};
|
||||
|
||||
EXPECT_EQ(false, atomic_boolean_.Get());
|
||||
|
||||
atomic_boolean_.Set(true);
|
||||
EXPECT_EQ(true, atomic_boolean_.Get());
|
||||
|
||||
thread::Fiber f([&] { EXPECT_EQ(true, atomic_boolean_.Get()); });
|
||||
f.Join();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,47 @@
|
||||
// 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 PLATFORM_IMPL_IOS_ATOMIC_UINT32_H_
|
||||
#define PLATFORM_IMPL_IOS_ATOMIC_UINT32_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
|
||||
#include "platform/api/atomic_reference.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
|
||||
// Concrete AtomicUint32 implementation.
|
||||
class AtomicUint32 : public api::AtomicUint32 {
|
||||
public:
|
||||
explicit AtomicUint32(std::uint32_t initial_value) : value_(initial_value) {}
|
||||
~AtomicUint32() override = default;
|
||||
|
||||
AtomicUint32(const AtomicUint32&) = delete;
|
||||
AtomicUint32& operator=(const AtomicUint32&) = delete;
|
||||
|
||||
std::uint32_t Get() const override { return value_; }
|
||||
void Set(std::uint32_t value) override { value_ = value; }
|
||||
|
||||
private:
|
||||
std::atomic<std::uint32_t> value_;
|
||||
};
|
||||
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_IMPL_IOS_ATOMIC_UINT32_H_
|
||||
@@ -0,0 +1,64 @@
|
||||
// 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 "platform/impl/ios/Source/Platform/atomic_uint32.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "thread/fiber/fiber.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
namespace {
|
||||
|
||||
TEST(AtomicUint32Test, GetOnSameThread) {
|
||||
std::uint32_t initial_value = 1450;
|
||||
AtomicUint32 atomic_reference_{initial_value};
|
||||
|
||||
EXPECT_EQ(initial_value, atomic_reference_.Get());
|
||||
}
|
||||
|
||||
TEST(AtomicUint32Test, SetGetOnSameThread) {
|
||||
std::uint32_t initial_value_ = 1450;
|
||||
AtomicUint32 atomic_reference_{initial_value_};
|
||||
|
||||
std::uint32_t new_value = 28;
|
||||
atomic_reference_.Set(new_value);
|
||||
EXPECT_EQ(new_value, atomic_reference_.Get());
|
||||
}
|
||||
|
||||
TEST(AtomicUint32Test, SetOnNewThread) {
|
||||
std::uint32_t initial_value_ = 1450;
|
||||
AtomicUint32 atomic_reference_{initial_value_};
|
||||
|
||||
std::uint32_t new_thread_value = 28;
|
||||
thread::Fiber f([&] { atomic_reference_.Set(new_thread_value); });
|
||||
f.Join();
|
||||
EXPECT_EQ(new_thread_value, atomic_reference_.Get());
|
||||
}
|
||||
|
||||
TEST(AtomicUint32Test, GetOnNewThread) {
|
||||
std::uint32_t initial_value_ = 1450;
|
||||
AtomicUint32 atomic_reference_{initial_value_};
|
||||
|
||||
std::uint32_t new_value = 28;
|
||||
atomic_reference_.Set(new_value);
|
||||
thread::Fiber f([&] { EXPECT_EQ(new_value, atomic_reference_.Get()); });
|
||||
f.Join();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,37 @@
|
||||
// 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 "platform/impl/ios/Source/Platform/condition_variable.h"
|
||||
|
||||
#include "platform/impl/ios/Source/Platform/mutex.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
|
||||
Exception ConditionVariable::Wait() {
|
||||
condition_variable_.Wait(mutex_);
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
Exception ConditionVariable::Wait(absl::Duration timeout) {
|
||||
condition_variable_.WaitWithTimeout(mutex_, timeout);
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
void ConditionVariable::Notify() { condition_variable_.SignalAll(); }
|
||||
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,48 @@
|
||||
// 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 PLATFORM_IMPL_IOS_CONDITION_VARIABLE_H_
|
||||
#define PLATFORM_IMPL_IOS_CONDITION_VARIABLE_H_
|
||||
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "platform/api/condition_variable.h"
|
||||
#include "platform/impl/ios/Source/Platform/mutex.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
|
||||
// Concrete ConditionVariable implementation.
|
||||
class ConditionVariable : public api::ConditionVariable {
|
||||
public:
|
||||
explicit ConditionVariable(ios::Mutex* mutex) : mutex_(&mutex->mutex_) {}
|
||||
~ConditionVariable() override = default;
|
||||
|
||||
ConditionVariable(const ConditionVariable&) = delete;
|
||||
ConditionVariable& operator=(const ConditionVariable&) = delete;
|
||||
|
||||
Exception Wait() override;
|
||||
Exception Wait(absl::Duration timeout) override;
|
||||
void Notify() override;
|
||||
|
||||
private:
|
||||
absl::Mutex* mutex_;
|
||||
absl::CondVar condition_variable_;
|
||||
};
|
||||
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_IMPL_IOS_CONDITION_VARIABLE_H_
|
||||
@@ -0,0 +1,84 @@
|
||||
// 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 "platform/impl/ios/Source/Platform/condition_variable.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/time/clock.h"
|
||||
#include "platform/impl/ios/Source/Platform/mutex.h"
|
||||
#include "thread/fiber/fiber.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
namespace {
|
||||
|
||||
TEST(ConditionVariableTest, CanCreate) {
|
||||
Mutex mutex{};
|
||||
ConditionVariable cond{&mutex};
|
||||
}
|
||||
|
||||
TEST(ConditionVariableTest, CanWakeupWaiter) {
|
||||
Mutex mutex{};
|
||||
ConditionVariable cond{&mutex};
|
||||
bool done = false;
|
||||
bool waiting = false;
|
||||
{
|
||||
thread::Fiber f([&cond, &mutex, &done, &waiting] {
|
||||
mutex.Lock();
|
||||
waiting = true;
|
||||
cond.Wait();
|
||||
waiting = false;
|
||||
done = true;
|
||||
mutex.Unlock();
|
||||
});
|
||||
while (true) {
|
||||
{
|
||||
mutex.Lock();
|
||||
if (waiting) {
|
||||
mutex.Unlock();
|
||||
break;
|
||||
}
|
||||
mutex.Unlock();
|
||||
}
|
||||
absl::SleepFor(absl::Milliseconds(100));
|
||||
}
|
||||
{
|
||||
mutex.Lock();
|
||||
cond.Notify();
|
||||
EXPECT_FALSE(done);
|
||||
mutex.Unlock();
|
||||
}
|
||||
f.Join();
|
||||
}
|
||||
EXPECT_TRUE(done);
|
||||
}
|
||||
|
||||
TEST(ConditionVariableTest, WaitTerminatesOnTimeoutWithoutNotify) {
|
||||
Mutex mutex{};
|
||||
ConditionVariable cond{&mutex};
|
||||
mutex.Lock();
|
||||
|
||||
const absl::Duration kWaitTime = absl::Milliseconds(100);
|
||||
absl::Time start = absl::Now();
|
||||
cond.Wait(kWaitTime);
|
||||
absl::Duration duration = absl::Now() - start;
|
||||
EXPECT_GE(duration, kWaitTime);
|
||||
mutex.Unlock();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,40 @@
|
||||
// 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 "platform/impl/ios/Source/Platform/count_down_latch.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
|
||||
Exception CountDownLatch::Await() {
|
||||
absl::MutexLock lock(&mutex_, absl::Condition(IsZeroOrNegative, &count_));
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
ExceptionOr<bool> CountDownLatch::Await(absl::Duration timeout) {
|
||||
bool condition = mutex_.LockWhenWithTimeout(
|
||||
absl::Condition(IsZeroOrNegative, &count_), timeout);
|
||||
mutex_.Unlock();
|
||||
return ExceptionOr<bool>(condition);
|
||||
}
|
||||
|
||||
void CountDownLatch::CountDown() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
count_--;
|
||||
}
|
||||
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,49 @@
|
||||
// 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 PLATFORM_IMPL_IOS_COUNT_DOWN_LATCH_H_
|
||||
#define PLATFORM_IMPL_IOS_COUNT_DOWN_LATCH_H_
|
||||
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "platform/api/count_down_latch.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
|
||||
// Concrete CountDownLatch implementation.
|
||||
class CountDownLatch : public api::CountDownLatch {
|
||||
public:
|
||||
explicit CountDownLatch(int count) : count_(count) {}
|
||||
~CountDownLatch() override = default;
|
||||
|
||||
CountDownLatch(const CountDownLatch&) = delete;
|
||||
CountDownLatch& operator=(const CountDownLatch&) = delete;
|
||||
|
||||
Exception Await() override;
|
||||
ExceptionOr<bool> Await(absl::Duration timeout) override;
|
||||
void CountDown() override;
|
||||
|
||||
private:
|
||||
static bool IsZeroOrNegative(int* count) { return 0 >= *count; }
|
||||
|
||||
absl::Mutex mutex_;
|
||||
int count_ ABSL_GUARDED_BY(mutex_);
|
||||
};
|
||||
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_IMPL_IOS_COUNT_DOWN_LATCH_H_
|
||||
@@ -0,0 +1,83 @@
|
||||
// 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 "platform/impl/ios/Source/Platform/count_down_latch.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "thread/fiber/fiber.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
namespace {
|
||||
|
||||
TEST(CountDownLatchTest, LatchAwaitCanWait) {
|
||||
CountDownLatch latch(1);
|
||||
std::atomic_bool done = false;
|
||||
|
||||
thread::Fiber f([&done, &latch] {
|
||||
done = true;
|
||||
latch.CountDown();
|
||||
});
|
||||
f.Join();
|
||||
|
||||
latch.Await();
|
||||
EXPECT_TRUE(done);
|
||||
}
|
||||
|
||||
TEST(CountDownLatchTest, LatchExtraCountDownIgnored) {
|
||||
CountDownLatch latch(1);
|
||||
std::atomic_bool done = false;
|
||||
|
||||
thread::Fiber f([&done, &latch] {
|
||||
done = true;
|
||||
latch.CountDown();
|
||||
latch.CountDown();
|
||||
latch.CountDown();
|
||||
});
|
||||
f.Join();
|
||||
|
||||
latch.Await();
|
||||
EXPECT_TRUE(done);
|
||||
}
|
||||
|
||||
TEST(CountDownLatchTest, LatchAwaitWithTimeoutCanExpire) {
|
||||
CountDownLatch latch(1);
|
||||
|
||||
auto response = latch.Await(absl::Milliseconds(100));
|
||||
|
||||
EXPECT_TRUE(response.ok());
|
||||
EXPECT_FALSE(response.result());
|
||||
}
|
||||
|
||||
TEST(CountDownLatchTest, InitialCountZero_AwaitDoesNotBlock) {
|
||||
CountDownLatch latch(0);
|
||||
|
||||
auto response = latch.Await();
|
||||
|
||||
EXPECT_TRUE(response.Ok());
|
||||
}
|
||||
|
||||
TEST(CountDownLatchTest, InitialCountNegative_AwaitDoesNotBlock) {
|
||||
CountDownLatch latch(-1);
|
||||
|
||||
auto response = latch.Await();
|
||||
|
||||
EXPECT_TRUE(response.Ok());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,39 @@
|
||||
// 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 "third_party/nearby_connections/cpp/platform/api/crypto.h"
|
||||
|
||||
#import "third_party/absl/strings/string_view.h"
|
||||
#import "third_party/nearby_connections/cpp/platform/impl/ios/Source/Platform/utils.h"
|
||||
#import "third_party/nearby_connections/cpp/platform/impl/ios/Source/Shared/GNCUtils.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
void Crypto::Init() {}
|
||||
|
||||
ByteArray Crypto::Md5(absl::string_view input) {
|
||||
if (input.empty()) return ByteArray();
|
||||
|
||||
return ByteArrayFromNSData(GNCMd5String(ObjCStringFromCppString(input)));
|
||||
}
|
||||
|
||||
ByteArray Crypto::Sha256(absl::string_view input) {
|
||||
if (input.empty()) return ByteArray();
|
||||
|
||||
return ByteArrayFromNSData(GNCSha256String(ObjCStringFromCppString(input)));
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,48 @@
|
||||
// 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 PLATFORM_IMPL_IOS_INPUT_FILE_H_
|
||||
#define PLATFORM_IMPL_IOS_INPUT_FILE_H_
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include "platform/api/input_file.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
|
||||
/** This InputFile subclass takes input from an NSURL. */
|
||||
class InputFile : public api::InputFile {
|
||||
public:
|
||||
explicit InputFile(NSURL *nsURL);
|
||||
~InputFile() override = default;
|
||||
InputFile(InputFile &&) = default;
|
||||
InputFile &operator=(InputFile &&) = default;
|
||||
|
||||
ExceptionOr<ByteArray> Read(std::int64_t size) override;
|
||||
std::string GetFilePath() const override;
|
||||
std::int64_t GetTotalSize() const override;
|
||||
Exception Close() override;
|
||||
|
||||
private:
|
||||
NSURL *nsURL_;
|
||||
NSInputStream *nsStream_;
|
||||
};
|
||||
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_IMPL_IOS_INPUT_FILE_H_
|
||||
@@ -0,0 +1,69 @@
|
||||
// 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.
|
||||
|
||||
#import "third_party/nearby_connections/cpp/platform/impl/ios/Source/Platform/input_file.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#import "third_party/nearby_connections/cpp/platform/base/exception.h"
|
||||
#import "third_party/nearby_connections/cpp/platform/impl/ios/Source/Platform/utils.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
|
||||
InputFile::InputFile(NSURL *nsURL) : nsURL_(nsURL) {
|
||||
std::string string = CppStringFromObjCString([nsURL_ absoluteString]);
|
||||
nsStream_ = [NSInputStream inputStreamWithURL:nsURL_];
|
||||
[nsStream_ scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
|
||||
[nsStream_ open];
|
||||
}
|
||||
|
||||
ExceptionOr<ByteArray> InputFile::Read(std::int64_t size) {
|
||||
uint8_t *bytes_read = new uint8_t[size];
|
||||
NSUInteger numberOfBytesToRead = [[NSNumber numberWithLongLong:size] unsignedIntegerValue];
|
||||
NSInteger numberOfBytesRead = [nsStream_ read:bytes_read maxLength:numberOfBytesToRead];
|
||||
if (numberOfBytesRead == 0) {
|
||||
// Reached end of stream.
|
||||
return ExceptionOr<ByteArray>();
|
||||
} else if (numberOfBytesRead < 0) {
|
||||
// Stream error.
|
||||
return ExceptionOr<ByteArray>(Exception::kIo);
|
||||
}
|
||||
return ExceptionOr<ByteArray>(ByteArrayFromNSData([NSData dataWithBytes:bytes_read
|
||||
length:numberOfBytesRead]));
|
||||
}
|
||||
|
||||
std::string InputFile::GetFilePath() const {
|
||||
return CppStringFromObjCString([nsURL_ absoluteString]);
|
||||
}
|
||||
|
||||
std::int64_t InputFile::GetTotalSize() const {
|
||||
NSNumber *fileSizeValue = nil;
|
||||
BOOL result = [nsURL_ getResourceValue:&fileSizeValue forKey:NSURLFileSizeKey error:nil];
|
||||
if (result) {
|
||||
return fileSizeValue.longValue;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Exception InputFile::Close() {
|
||||
[nsStream_ close];
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,47 @@
|
||||
// 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 PLATFORM_IMPL_IOS_LOG_MESSAGE_H_
|
||||
#define PLATFORM_IMPL_IOS_LOG_MESSAGE_H_
|
||||
|
||||
#include "base/check.h"
|
||||
#include "platform/api/log_message.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
|
||||
// Concrete LogMessage implementation
|
||||
class LogMessage : public api::LogMessage {
|
||||
public:
|
||||
LogMessage(const char* file, int line, Severity severity);
|
||||
~LogMessage() override = default;
|
||||
|
||||
LogMessage(const LogMessage&) = delete;
|
||||
LogMessage& operator=(const LogMessage&) = delete;
|
||||
|
||||
void Print(const char* format, ...) override;
|
||||
|
||||
std::ostream& Stream() override;
|
||||
|
||||
private:
|
||||
absl::LogStreamer log_streamer_;
|
||||
api::LogMessage::Severity severity_;
|
||||
};
|
||||
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // IPHONE_SHARED_NEARBY_CONNECTIONS_SOURCE_PLATFORM_LOG_MESSAGE_H_
|
||||
@@ -0,0 +1,87 @@
|
||||
// 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 "third_party/nearby_connections/cpp/platform/impl/ios/Source/Platform/log_message.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "third_party/nearby_connections/cpp/platform/api/log_message.h"
|
||||
#include "third_party/objective_c/google_toolbox_for_mac/Foundation/GTMLogger.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
|
||||
api::LogMessage::Severity gMinLogSeverity = api::LogMessage::Severity::kInfo;
|
||||
|
||||
GTMLoggerLevel ConvertSeverity(api::LogMessage::Severity severity) {
|
||||
switch (severity) {
|
||||
case api::LogMessage::Severity::kVerbose:
|
||||
return kGTMLoggerLevelDebug;
|
||||
case api::LogMessage::Severity::kInfo:
|
||||
return kGTMLoggerLevelInfo;
|
||||
case api::LogMessage::Severity::kWarning:
|
||||
return kGTMLoggerLevelInfo;
|
||||
case api::LogMessage::Severity::kError:
|
||||
return kGTMLoggerLevelError;
|
||||
case api::LogMessage::Severity::kFatal:
|
||||
return kGTMLoggerLevelAssert;
|
||||
}
|
||||
}
|
||||
|
||||
LogMessage::LogMessage(const char* file, int line, Severity severity)
|
||||
: log_streamer_(ConvertSeverity(severity), file, line), severity_(severity) {}
|
||||
|
||||
void LogMessage::Print(const char* format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
switch (ConvertSeverity(severity_)) {
|
||||
case kGTMLoggerLevelDebug:
|
||||
[[GTMLogger sharedLogger] logDebug:[NSString stringWithUTF8String:format], ap];
|
||||
break;
|
||||
case kGTMLoggerLevelInfo:
|
||||
[[GTMLogger sharedLogger] logInfo:[NSString stringWithUTF8String:format], ap];
|
||||
break;
|
||||
case kGTMLoggerLevelError:
|
||||
[[GTMLogger sharedLogger] logError:[NSString stringWithUTF8String:format], ap];
|
||||
break;
|
||||
case kGTMLoggerLevelAssert:
|
||||
[[GTMLogger sharedLogger] logAssert:[NSString stringWithUTF8String:format], ap];
|
||||
break;
|
||||
case kGTMLoggerLevelUnknown:
|
||||
// no-op
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/169292092): GTMLogger doesn't support stream. Temporarily use absl LogStreamer to make
|
||||
// build pass.
|
||||
std::ostream& LogMessage::Stream() { return log_streamer_.stream(); }
|
||||
|
||||
} // namespace ios
|
||||
|
||||
namespace api {
|
||||
|
||||
// static
|
||||
void LogMessage::SetMinLogSeverity(Severity severity) { ios::gMinLogSeverity = severity; }
|
||||
|
||||
// static
|
||||
bool LogMessage::ShouldCreateLogMessage(Severity severity) {
|
||||
// TODO(b/169292092): GTMLogger doesn't support stream which cause crash. Temporarily turn off
|
||||
// LogMessage.
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,47 @@
|
||||
// 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 PLATFORM_IMPL_IOS_MULTI_THREAD_EXECUTOR_H_
|
||||
#define PLATFORM_IMPL_IOS_MULTI_THREAD_EXECUTOR_H_
|
||||
|
||||
#include "platform/api/submittable_executor.h"
|
||||
#import "third_party/nearby_connections/cpp/platform/base/runnable.h"
|
||||
#import "third_party/nearby_connections/cpp/platform/impl/ios/Source/Platform/scheduled_executor.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
|
||||
class MultiThreadExecutor : public api::SubmittableExecutor {
|
||||
public:
|
||||
explicit MultiThreadExecutor(int max_concurrency);
|
||||
~MultiThreadExecutor() override = default;
|
||||
|
||||
MultiThreadExecutor(const MultiThreadExecutor&) = delete;
|
||||
MultiThreadExecutor& operator=(const MultiThreadExecutor&) = delete;
|
||||
|
||||
// api::SubmittableExecutor:
|
||||
void Shutdown() override;
|
||||
void Execute(Runnable&& runnable) override;
|
||||
bool DoSubmit(Runnable&& runnable) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<ScheduledExecutor> scheduled_executor_;
|
||||
};
|
||||
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_IMPL_IOS_MULTI_THREAD_EXECUTOR_H_
|
||||
@@ -0,0 +1,40 @@
|
||||
// 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.
|
||||
|
||||
#import "third_party/nearby_connections/cpp/platform/impl/ios/Source/Platform/multi_thread_executor.h"
|
||||
|
||||
#include "third_party/nearby_connections/cpp/platform/base/runnable.h"
|
||||
#import "third_party/nearby_connections/cpp/platform/impl/ios/Source/Platform/scheduled_executor.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
|
||||
MultiThreadExecutor::MultiThreadExecutor(int max_concurrency) {
|
||||
scheduled_executor_ = std::make_unique<ScheduledExecutor>(max_concurrency);
|
||||
}
|
||||
|
||||
void MultiThreadExecutor::Shutdown() { scheduled_executor_->Shutdown(); }
|
||||
|
||||
void MultiThreadExecutor::Execute(Runnable&& runnable) {
|
||||
scheduled_executor_->Execute(std::move(runnable));
|
||||
}
|
||||
|
||||
bool MultiThreadExecutor::DoSubmit(Runnable&& runnable) {
|
||||
return scheduled_executor_->DoSubmit(std::move(runnable));
|
||||
}
|
||||
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,84 @@
|
||||
// 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 PLATFORM_IMPL_IOS_MUTEX_H_
|
||||
#define PLATFORM_IMPL_IOS_MUTEX_H_
|
||||
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "platform/api/mutex.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
|
||||
// Concrete Mutex implementation.
|
||||
class ABSL_LOCKABLE Mutex : public api::Mutex {
|
||||
public:
|
||||
explicit Mutex() {}
|
||||
~Mutex() override = default;
|
||||
|
||||
Mutex(const Mutex&) = delete;
|
||||
Mutex& operator=(const Mutex&) = delete;
|
||||
|
||||
void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() override {
|
||||
mutex_.Lock();
|
||||
mutex_.ForgetDeadlockInfo();
|
||||
}
|
||||
void Unlock() ABSL_UNLOCK_FUNCTION() override { mutex_.Unlock(); }
|
||||
|
||||
private:
|
||||
friend class ConditionVariable;
|
||||
absl::Mutex mutex_;
|
||||
};
|
||||
|
||||
class ABSL_LOCKABLE RecursiveMutex : public api::Mutex {
|
||||
public:
|
||||
RecursiveMutex() = default;
|
||||
~RecursiveMutex() override = default;
|
||||
|
||||
RecursiveMutex(RecursiveMutex&&) = delete;
|
||||
RecursiveMutex& operator=(RecursiveMutex&&) = delete;
|
||||
|
||||
void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() override {
|
||||
intptr_t thread_id = ThreadId();
|
||||
if (thread_id_.load(std::memory_order_acquire) != thread_id) {
|
||||
mutex_.Lock();
|
||||
thread_id_.store(thread_id, std::memory_order_release);
|
||||
}
|
||||
++count_;
|
||||
}
|
||||
|
||||
void Unlock() ABSL_UNLOCK_FUNCTION() override {
|
||||
if (--count_ == 0) {
|
||||
thread_id_.store(0, std::memory_order_release);
|
||||
mutex_.Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static inline intptr_t ThreadId() {
|
||||
ABSL_CONST_INIT thread_local int per_thread = 0;
|
||||
return reinterpret_cast<intptr_t>(&per_thread);
|
||||
}
|
||||
|
||||
std::atomic<intptr_t> thread_id_{0};
|
||||
int count_{0};
|
||||
absl::Mutex mutex_;
|
||||
};
|
||||
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_IMPL_IOS_MUTEX_H_
|
||||
@@ -0,0 +1,92 @@
|
||||
// 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 "platform/impl/ios/Source/Platform/mutex.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "absl/synchronization/notification.h"
|
||||
#include "absl/time/clock.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "thread/fiber/fiber.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
namespace {
|
||||
|
||||
static const absl::Duration kTimeToWait = absl::Milliseconds(500);
|
||||
|
||||
TEST(MutexTest, LockOnce_UnlockOnce) {
|
||||
Mutex test_mutex_1{};
|
||||
test_mutex_1.Lock();
|
||||
test_mutex_1.Unlock();
|
||||
|
||||
RecursiveMutex test_mutex_2;
|
||||
test_mutex_2.Lock();
|
||||
test_mutex_2.Unlock();
|
||||
}
|
||||
|
||||
TEST(MutexTest, BasicLockingWorks) {
|
||||
absl::Notification lock_obtained;
|
||||
Mutex test_mutex{};
|
||||
test_mutex.Lock();
|
||||
thread::Fiber f([&test_mutex, &lock_obtained] {
|
||||
test_mutex.Lock();
|
||||
test_mutex.Unlock();
|
||||
lock_obtained.Notify();
|
||||
});
|
||||
EXPECT_FALSE(lock_obtained.WaitForNotificationWithTimeout(kTimeToWait));
|
||||
test_mutex.Unlock();
|
||||
EXPECT_TRUE(lock_obtained.WaitForNotificationWithTimeout(kTimeToWait));
|
||||
f.Join();
|
||||
}
|
||||
|
||||
TEST(MutexTest, RecursiveLockingWorks) {
|
||||
absl::Notification lock_obtained;
|
||||
RecursiveMutex test_mutex;
|
||||
test_mutex.Lock();
|
||||
thread::Fiber f([&test_mutex, &lock_obtained] {
|
||||
test_mutex.Lock();
|
||||
test_mutex.Unlock();
|
||||
lock_obtained.Notify();
|
||||
});
|
||||
EXPECT_FALSE(lock_obtained.WaitForNotificationWithTimeout(kTimeToWait));
|
||||
test_mutex.Unlock();
|
||||
EXPECT_TRUE(lock_obtained.WaitForNotificationWithTimeout(kTimeToWait));
|
||||
f.Join();
|
||||
}
|
||||
|
||||
TEST(MutexTest, RecursiveLockingForNestedWorks) {
|
||||
absl::Notification lock_obtained;
|
||||
RecursiveMutex test_mutex;
|
||||
test_mutex.Lock();
|
||||
thread::Fiber f([&test_mutex, &lock_obtained]()
|
||||
ABSL_NO_THREAD_SAFETY_ANALYSIS {
|
||||
test_mutex.Lock();
|
||||
test_mutex.Lock();
|
||||
test_mutex.Unlock();
|
||||
test_mutex.Unlock();
|
||||
lock_obtained.Notify();
|
||||
});
|
||||
EXPECT_FALSE(lock_obtained.WaitForNotificationWithTimeout(kTimeToWait));
|
||||
test_mutex.Unlock();
|
||||
EXPECT_TRUE(lock_obtained.WaitForNotificationWithTimeout(kTimeToWait));
|
||||
f.Join();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,68 @@
|
||||
// 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 PLATFORM_IMPL_IOS_SCHEDULED_EXECUTOR_H_
|
||||
#define PLATFORM_IMPL_IOS_SCHEDULED_EXECUTOR_H_
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "platform/api/scheduled_executor.h"
|
||||
#include "platform/base/runnable.h"
|
||||
|
||||
/**
|
||||
* The impl class is an Obj-C class so that
|
||||
* (a) the dispatch block can strongly retain it, and
|
||||
* (b) for ease of declaring an atomic property.
|
||||
*/
|
||||
@interface GNCOperationQueueImpl : NSObject
|
||||
@property(nonatomic) NSOperationQueue* queue;
|
||||
@property(atomic) BOOL shuttingDown;
|
||||
@end
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
|
||||
// Concrete ScheduledExecutor implementation.
|
||||
class ScheduledExecutor : public api::ScheduledExecutor {
|
||||
public:
|
||||
// The max_concurrency = 1 for default constructor.
|
||||
ScheduledExecutor();
|
||||
explicit ScheduledExecutor(int max_concurrency);
|
||||
~ScheduledExecutor() override;
|
||||
|
||||
ScheduledExecutor(const ScheduledExecutor&) = delete;
|
||||
ScheduledExecutor& operator=(const ScheduledExecutor&) = delete;
|
||||
|
||||
// api::ScheduledExecutor:
|
||||
void Shutdown() override;
|
||||
std::shared_ptr<api::Cancelable> Schedule(Runnable&& runnable, absl::Duration duration) override;
|
||||
void Execute(Runnable&& runnable) override;
|
||||
|
||||
bool DoSubmit(Runnable&& runnable);
|
||||
|
||||
private:
|
||||
void Shutdown(std::int64_t timeout_millis);
|
||||
|
||||
GNCOperationQueueImpl* impl_;
|
||||
};
|
||||
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_IMPL_IOS_SCHEDULED_EXECUTOR_H_
|
||||
@@ -0,0 +1,144 @@
|
||||
// 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.
|
||||
|
||||
#import "third_party/nearby_connections/cpp/platform/impl/ios/Source/Platform/scheduled_executor.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include "third_party/absl/time/time.h"
|
||||
#include "third_party/nearby_connections/cpp/platform/base/runnable.h"
|
||||
#import "third_party/nearby_connections/cpp/platform/impl/ios/Source/Platform/atomic_boolean.h"
|
||||
|
||||
// This wraps the C++ Runnable in an Obj-C object for memory management. It is retained by the
|
||||
// dispatch block below, and deleted when the block is released.
|
||||
@interface GNCRunnableWrapper : NSObject {
|
||||
@public
|
||||
location::nearby::Runnable _runnable;
|
||||
std::unique_ptr<location::nearby::ios::AtomicBoolean> _canceled;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation GNCRunnableWrapper
|
||||
|
||||
+ (instancetype)wrapperWithRunnable:(location::nearby::Runnable)runnable {
|
||||
GNCRunnableWrapper *wrapper = [[GNCRunnableWrapper alloc] init];
|
||||
wrapper->_runnable = runnable;
|
||||
wrapper->_canceled = std::make_unique<location::nearby::ios::AtomicBoolean>(false);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GNCOperationQueueImpl
|
||||
|
||||
+ (instancetype)implWithMaxConcurrency:(int)maxConcurrency {
|
||||
GNCOperationQueueImpl *impl = [[GNCOperationQueueImpl alloc] init];
|
||||
impl.queue = [[NSOperationQueue alloc] init];
|
||||
impl.queue.maxConcurrentOperationCount = maxConcurrency;
|
||||
return impl;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
|
||||
static const std::int64_t kExecutorShutdownDefaultTimeout = 500; // 0.5 seconds
|
||||
|
||||
// This Cancelable references a Runnable and a cancel method that sets its canceled boolean to true.
|
||||
class CancelableForRunnable : public api::Cancelable {
|
||||
public:
|
||||
explicit CancelableForRunnable(GNCRunnableWrapper *runnable) : runnable_(runnable) {}
|
||||
CancelableForRunnable() = default;
|
||||
~CancelableForRunnable() override = default;
|
||||
CancelableForRunnable(const CancelableForRunnable &) = delete;
|
||||
CancelableForRunnable &operator=(const CancelableForRunnable &) = delete;
|
||||
|
||||
// api::Cancelable:
|
||||
bool Cancel() override {
|
||||
runnable_->_canceled->Set(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
GNCRunnableWrapper *runnable_;
|
||||
};
|
||||
|
||||
ScheduledExecutor::ScheduledExecutor() { impl_ = [GNCOperationQueueImpl implWithMaxConcurrency:1]; }
|
||||
|
||||
ScheduledExecutor::ScheduledExecutor(int max_concurrency) {
|
||||
impl_ = [GNCOperationQueueImpl implWithMaxConcurrency:max_concurrency];
|
||||
}
|
||||
|
||||
ScheduledExecutor::~ScheduledExecutor() { impl_ = nil; }
|
||||
|
||||
void ScheduledExecutor::Shutdown() { Shutdown(kExecutorShutdownDefaultTimeout); }
|
||||
|
||||
std::shared_ptr<api::Cancelable> ScheduledExecutor::Schedule(Runnable &&runnable,
|
||||
absl::Duration duration) {
|
||||
if (impl_.shuttingDown) return std::shared_ptr<api::Cancelable>(nullptr);
|
||||
|
||||
// Wrap the runnable in an Obj-C object so it can be referenced by the delayed block.
|
||||
GNCRunnableWrapper *wrapper = [GNCRunnableWrapper wrapperWithRunnable:std::move(runnable)];
|
||||
CancelableForRunnable *cancelable = new CancelableForRunnable(wrapper);
|
||||
GNCOperationQueueImpl *impl = impl_; // don't capture |this|
|
||||
dispatch_after(
|
||||
dispatch_time(DISPATCH_TIME_NOW, absl::ToInt64Milliseconds(duration) * NSEC_PER_MSEC),
|
||||
dispatch_get_global_queue(DISPATCH_TARGET_QUEUE_DEFAULT, 0), ^{
|
||||
[impl.queue addOperationWithBlock:^{
|
||||
// Execute the runnable only if the executor is not shutting down, and the runnable isn't
|
||||
// canceled.
|
||||
// Warning: This block should reference only Obj-C objects, and never C++ objects.
|
||||
if (!impl.shuttingDown && !wrapper->_canceled->Get()) {
|
||||
wrapper->_runnable();
|
||||
}
|
||||
}];
|
||||
});
|
||||
|
||||
return std::shared_ptr<api::Cancelable>(cancelable);
|
||||
}
|
||||
|
||||
void ScheduledExecutor::Execute(Runnable &&runnable) {
|
||||
DoSubmit(std::move(runnable));
|
||||
}
|
||||
|
||||
bool ScheduledExecutor::DoSubmit(Runnable &&runnable) {
|
||||
if (impl_.shuttingDown) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Submit the runnable to the queue.
|
||||
Runnable local_runnable = std::move(runnable);
|
||||
[impl_.queue addOperationWithBlock:^{
|
||||
local_runnable();
|
||||
}];
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScheduledExecutor::Shutdown(std::int64_t timeout_millis) {
|
||||
// Prevent new/delayed operations from being queued/executed.
|
||||
impl_.shuttingDown = YES;
|
||||
|
||||
// Block until either (a) all currently executing operations finish, or (b) the timeout expires.
|
||||
dispatch_group_t group = dispatch_group_create();
|
||||
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_TARGET_QUEUE_DEFAULT, 0), ^{
|
||||
[impl_.queue waitUntilAllOperationsAreFinished];
|
||||
});
|
||||
dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, timeout_millis * NSEC_PER_MSEC));
|
||||
}
|
||||
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,35 @@
|
||||
// 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 PLATFORM_IMPL_IOS_SINGLE_THREAD_EXECUTOR_H_
|
||||
#define PLATFORM_IMPL_IOS_SINGLE_THREAD_EXECUTOR_H_
|
||||
|
||||
#import "third_party/nearby_connections/cpp/platform/impl/ios/Source/Platform/multi_thread_executor.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
|
||||
class SingleThreadExecutor : public MultiThreadExecutor {
|
||||
public:
|
||||
SingleThreadExecutor() : MultiThreadExecutor(1) {}
|
||||
~SingleThreadExecutor() override = default;
|
||||
};
|
||||
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_IMPL_IOS_SINGLE_THREAD_EXECUTOR_H_
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// 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 "platform/api/system_clock.h"
|
||||
|
||||
#include "absl/time/clock.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
void SystemClock::Init() {}
|
||||
|
||||
absl::Time SystemClock::ElapsedRealtime() { return absl::Now(); }
|
||||
|
||||
// TODO(b/169292092): Check the iOS primitive implementation for SystemClock.
|
||||
Exception SystemClock::Sleep(absl::Duration duration) {
|
||||
absl::SleepFor(duration);
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,74 @@
|
||||
// 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.
|
||||
|
||||
#import <CoreBluetooth/CoreBluetooth.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "platform/base/byte_array.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
/// Converts an Obj-C BOOL to a C++ bool.
|
||||
bool CppBoolFromObjCBool(BOOL b);
|
||||
|
||||
/// Converts NSNumber to a char.
|
||||
char CharFromNSNumber(NSNumber *n);
|
||||
|
||||
/// Converts a C++ string to an Obj-C string.
|
||||
NSString *ObjCStringFromCppString(absl::string_view s);
|
||||
|
||||
/// Converts an Obj-C string to a C++ string.
|
||||
std::string CppStringFromObjCString(NSString *s);
|
||||
|
||||
/// Converts ByteArray to NSData.
|
||||
NSData *NSDataFromByteArray(ByteArray byteArray);
|
||||
|
||||
/// Converts NSData to ByteArray.
|
||||
ByteArray ByteArrayFromNSData(NSData *data);
|
||||
|
||||
/// Converts NSUUID to a C++ string (representing a UUID).
|
||||
std::string UUIDStringFromNSUUID(NSUUID *uuid);
|
||||
|
||||
/// Converts a C++ string (representing a Bluetooth UUID) to CBUUID.
|
||||
CBUUID *CBUUIDFromBluetoothUUIDString(absl::string_view bluetoothUUID);
|
||||
|
||||
/// Converts CBUUID to a C++ string (representing a Bluetooth UUID).
|
||||
std::string BluetoothUUIDStringFromCBUUID(CBUUID *bluetoothUUID);
|
||||
|
||||
/// Converts a C++ set of strings (representing Bluetooth UUIDs) to an NSSet of CBUUID.
|
||||
NSSet<CBUUID *> *CBUUIDSetFromBluetoothUUIDStringSet(const std::set<std::string> &bluetoothUUIDSet);
|
||||
|
||||
/// Converts an NSSet of CBUUID to a C++ set of strings (representing Bluetooth UUIDs).
|
||||
std::set<std::string> BluetoothUUIDStringSetFromCBUUIDSet(NSSet<CBUUID *> *bluetoothUUIDSet);
|
||||
|
||||
/// Converts a C++ TxtRecord to an Obj-C TxtRecord.
|
||||
NSDictionary<NSString *, NSData *> *NSDictionaryFromCppTxtRecords(
|
||||
const absl::flat_hash_map<std::string, std::string> &txt_records);
|
||||
|
||||
/// Converts an Obj-C TxtRecord to a C++ TxtRecord.
|
||||
absl::flat_hash_map<std::string, std::string> AbslHashMapFromObjCTxtRecords(
|
||||
NSDictionary<NSString *, NSData *> *txtRecords);
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,104 @@
|
||||
// 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.
|
||||
|
||||
#import "third_party/nearby_connections/cpp/platform/impl/ios/Source/Platform/utils.h"
|
||||
|
||||
#import "third_party/absl/container/flat_hash_map.h"
|
||||
#include "third_party/absl/strings/string_view.h"
|
||||
#include "third_party/nearby_connections/cpp/platform/base/byte_array.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
bool CppBoolFromObjCBool(BOOL b) { return b ? true : false; }
|
||||
|
||||
char CharFromNSNumber(NSNumber* n) { return n.charValue; }
|
||||
|
||||
NSString* ObjCStringFromCppString(absl::string_view s) {
|
||||
return [NSString stringWithUTF8String:s.data()];
|
||||
}
|
||||
|
||||
std::string CppStringFromObjCString(NSString* s) {
|
||||
return std::string([s UTF8String], [s lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
|
||||
}
|
||||
|
||||
NSData* NSDataFromByteArray(ByteArray byteArray) {
|
||||
return [NSData dataWithBytes:byteArray.data() length:byteArray.size()];
|
||||
}
|
||||
|
||||
ByteArray ByteArrayFromNSData(NSData* data) {
|
||||
return ByteArray((const char*)data.bytes, data.length);
|
||||
}
|
||||
|
||||
std::string UUIDStringFromNSUUID(NSUUID* uuid) { return CppStringFromObjCString(uuid.UUIDString); }
|
||||
|
||||
CBUUID* CBUUIDFromBluetoothUUIDString(absl::string_view bluetoothUUID) {
|
||||
return [CBUUID UUIDWithString:ObjCStringFromCppString(bluetoothUUID)];
|
||||
}
|
||||
|
||||
std::string BluetoothUUIDStringFromCBUUID(CBUUID* bluetoothUUID) {
|
||||
return CppStringFromObjCString(bluetoothUUID.UUIDString);
|
||||
}
|
||||
|
||||
NSSet<CBUUID*>* CBUUIDSetFromBluetoothUUIDStringSet(const std::set<std::string>& bluetoothUUIDSet) {
|
||||
NSMutableSet<CBUUID*>* objcBluetoothUUIDSet = [NSMutableSet set];
|
||||
for (std::set<std::string>::const_iterator it = bluetoothUUIDSet.begin();
|
||||
it != bluetoothUUIDSet.end(); ++it) {
|
||||
[objcBluetoothUUIDSet addObject:CBUUIDFromBluetoothUUIDString(*it)];
|
||||
}
|
||||
return objcBluetoothUUIDSet;
|
||||
}
|
||||
|
||||
std::set<std::string> BluetoothUUIDStringSetFromCBUUIDSet(NSSet<CBUUID*>* bluetoothUUIDSet) {
|
||||
std::set<std::string> cppBluetoothUUIDSet;
|
||||
for (CBUUID* bluetoothUUID in bluetoothUUIDSet) {
|
||||
cppBluetoothUUIDSet.insert(BluetoothUUIDStringFromCBUUID(bluetoothUUID));
|
||||
}
|
||||
return cppBluetoothUUIDSet;
|
||||
}
|
||||
|
||||
NSDictionary<NSString*, NSData*>* NSDictionaryFromCppTxtRecords(
|
||||
const absl::flat_hash_map<std::string, std::string>& txt_records) {
|
||||
NSMutableArray<NSString*>* keyArray = [[NSMutableArray alloc] init];
|
||||
NSMutableArray<NSData*>* valueArray = [[NSMutableArray alloc] init];
|
||||
for (auto it = txt_records.begin(); it != txt_records.end(); it++) {
|
||||
NSString* key = @(it->first.c_str());
|
||||
NSString* value = @(it->second.c_str());
|
||||
[keyArray addObject:key];
|
||||
[valueArray addObject:[value dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
}
|
||||
|
||||
NSDictionary<NSString*, NSData*>* dict = [[NSDictionary alloc] initWithObjects:valueArray
|
||||
forKeys:keyArray];
|
||||
return dict;
|
||||
}
|
||||
|
||||
absl::flat_hash_map<std::string, std::string> AbslHashMapFromObjCTxtRecords(
|
||||
NSDictionary<NSString*, NSData*>* txtRecords) {
|
||||
absl::flat_hash_map<std::string, std::string> txt_record;
|
||||
|
||||
for (NSString* key in txtRecords) {
|
||||
NSString* value = [[NSString alloc] initWithData:[txtRecords objectForKey:key]
|
||||
encoding:NSUTF8StringEncoding];
|
||||
txt_record.insert({CppStringFromObjCString(key), CppStringFromObjCString(value)});
|
||||
}
|
||||
return txt_record;
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -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.
|
||||
|
||||
#ifndef PLATFORM_IMPL_IOS_WIFI_LAN_H_
|
||||
#define PLATFORM_IMPL_IOS_WIFI_LAN_H_
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "platform/api/wifi_lan.h"
|
||||
#include "platform/base/nsd_service_info.h"
|
||||
#import "third_party/nearby_connections/cpp/platform/impl/ios/Source/Mediums/GNCMConnection.h" // IWYU pragma: export
|
||||
|
||||
@class GNCMBonjourBrowser;
|
||||
@class GNCMBonjourService;
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
|
||||
/** InputStream that reads from GNCMConnection. */
|
||||
class WifiLanInputStream : public InputStream {
|
||||
public:
|
||||
WifiLanInputStream();
|
||||
~WifiLanInputStream() override;
|
||||
|
||||
ExceptionOr<ByteArray> Read(std::int64_t size) override;
|
||||
Exception Close() override;
|
||||
|
||||
GNCMConnectionHandlers* GetConnectionHandlers() { return connectionHandlers_; }
|
||||
|
||||
private:
|
||||
GNCMConnectionHandlers* connectionHandlers_;
|
||||
NSMutableArray<NSData*>* newDataPackets_;
|
||||
NSMutableData* accumulatedData_;
|
||||
NSCondition* condition_;
|
||||
};
|
||||
|
||||
/** OutputStream that writes to GNCMConnection. */
|
||||
class WifiLanOutputStream : public OutputStream {
|
||||
public:
|
||||
explicit WifiLanOutputStream(id<GNCMConnection> connection)
|
||||
: connection_(connection), condition_([[NSCondition alloc] init]) {}
|
||||
~WifiLanOutputStream() override;
|
||||
|
||||
Exception Write(const ByteArray& data) override;
|
||||
Exception Flush() override;
|
||||
Exception Close() override;
|
||||
|
||||
private:
|
||||
id<GNCMConnection> connection_;
|
||||
NSCondition* condition_;
|
||||
};
|
||||
|
||||
/** Concrete WifiLanSocket implementation. */
|
||||
class WifiLanSocket : public api::WifiLanSocket {
|
||||
public:
|
||||
WifiLanSocket() = default;
|
||||
explicit WifiLanSocket(id<GNCMConnection> connection);
|
||||
~WifiLanSocket() override;
|
||||
|
||||
// api::WifiLanSocket:
|
||||
InputStream& GetInputStream() override { return *input_stream_; }
|
||||
OutputStream& GetOutputStream() override { return *output_stream_; }
|
||||
Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
private:
|
||||
void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
mutable absl::Mutex mutex_;
|
||||
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
|
||||
std::unique_ptr<WifiLanInputStream> input_stream_;
|
||||
std::unique_ptr<WifiLanOutputStream> output_stream_;
|
||||
};
|
||||
|
||||
/** Concrete WifiLanServerSocket implementation. */
|
||||
class WifiLanServerSocket : public api::WifiLanServerSocket {
|
||||
public:
|
||||
static std::string GetName(const std::string& ip_address, int port);
|
||||
|
||||
~WifiLanServerSocket() override;
|
||||
|
||||
// api::WifiLanServerSocket:
|
||||
std::string GetIPAddress() const override ABSL_LOCKS_EXCLUDED(mutex_) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return ip_address_;
|
||||
}
|
||||
void SetIPAddress(const std::string& ip_address) ABSL_LOCKS_EXCLUDED(mutex_) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
ip_address_ = ip_address;
|
||||
}
|
||||
int GetPort() const override ABSL_LOCKS_EXCLUDED(mutex_) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return port_;
|
||||
}
|
||||
void SetPort(int port) ABSL_LOCKS_EXCLUDED(mutex_) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
port_ = port;
|
||||
}
|
||||
std::unique_ptr<api::WifiLanSocket> Accept() override ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
bool Connect(std::unique_ptr<WifiLanSocket> socket) ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
void SetCloseNotifier(std::function<void()> notifier) ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
private:
|
||||
Exception DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
mutable absl::Mutex mutex_;
|
||||
std::string ip_address_ ABSL_GUARDED_BY(mutex_);
|
||||
int port_ ABSL_GUARDED_BY(mutex_);
|
||||
absl::CondVar cond_;
|
||||
absl::flat_hash_set<std::unique_ptr<WifiLanSocket>> pending_sockets_ ABSL_GUARDED_BY(mutex_);
|
||||
std::function<void()> close_notifier_ ABSL_GUARDED_BY(mutex_);
|
||||
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
|
||||
};
|
||||
|
||||
/** Concrete WifiLanMedium implementation. */
|
||||
class WifiLanMedium : public api::WifiLanMedium {
|
||||
public:
|
||||
WifiLanMedium() = default;
|
||||
~WifiLanMedium() override;
|
||||
|
||||
WifiLanMedium(const WifiLanMedium&) = delete;
|
||||
WifiLanMedium& operator=(const WifiLanMedium&) = delete;
|
||||
|
||||
// api::WifiLanMedium:
|
||||
bool StartAdvertising(const NsdServiceInfo& nsd_service_info) override
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
bool StopAdvertising(const NsdServiceInfo& nsd_service_info) override ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
bool StartDiscovery(const std::string& service_type, DiscoveredServiceCallback callback) override
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
bool StopDiscovery(const std::string& service_type) override ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
std::unique_ptr<api::WifiLanSocket> ConnectToService(
|
||||
const NsdServiceInfo& remote_service_info, CancellationFlag* cancellation_flag) override;
|
||||
std::unique_ptr<api::WifiLanSocket> ConnectToService(
|
||||
const std::string& ip_address, int port, CancellationFlag* cancellation_flag) override;
|
||||
std::unique_ptr<api::WifiLanServerSocket> ListenForService(int port) override
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
private:
|
||||
struct AdvertisingInfo {
|
||||
bool Empty() const { return services.empty(); }
|
||||
void Clear() { services.clear(); }
|
||||
void Add(const std::string& service_type, GNCMBonjourService* service) {
|
||||
services.insert({service_type, service});
|
||||
}
|
||||
void Remove(const std::string& service_type) { services.erase(service_type); }
|
||||
bool Existed(const std::string& service_type) const { return services.contains(service_type); }
|
||||
|
||||
absl::flat_hash_map<std::string, GNCMBonjourService*> services;
|
||||
};
|
||||
struct DiscoveringInfo {
|
||||
bool Empty() const { return services.empty(); }
|
||||
void Clear() { services.clear(); }
|
||||
void Add(const std::string& service_type, GNCMBonjourBrowser* browser) {
|
||||
services.insert({service_type, browser});
|
||||
}
|
||||
void Remove(const std::string& service_type) { services.erase(service_type); }
|
||||
bool Existed(const std::string& service_type) const { return services.contains(service_type); }
|
||||
|
||||
absl::flat_hash_map<std::string, GNCMBonjourBrowser*> services;
|
||||
};
|
||||
|
||||
std::string GetFakeIPAddress() const;
|
||||
int GetFakePort() const;
|
||||
|
||||
absl::Mutex mutex_;
|
||||
AdvertisingInfo advertising_info_ ABSL_GUARDED_BY(mutex_);
|
||||
int requesting_port_ = 0;
|
||||
DiscoveringInfo discovering_info_ ABSL_GUARDED_BY(mutex_);
|
||||
absl::flat_hash_map<std::string, WifiLanServerSocket*> server_sockets_ ABSL_GUARDED_BY(mutex_);
|
||||
absl::flat_hash_map<std::string, GNCMConnectionRequester> connection_requesters_
|
||||
ABSL_GUARDED_BY(mutex_);
|
||||
};
|
||||
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_IMPL_IOS_WIFI_LAN_H_
|
||||
@@ -0,0 +1,497 @@
|
||||
// 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.
|
||||
|
||||
#import "third_party/nearby_connections/cpp/platform/impl/ios/Source/Platform/wifi_lan.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "third_party/absl/container/flat_hash_map.h"
|
||||
#include "third_party/absl/container/internal/common.h"
|
||||
#include "third_party/absl/memory/memory.h"
|
||||
#include "third_party/absl/strings/str_cat.h"
|
||||
#include "third_party/absl/strings/str_format.h"
|
||||
#include "third_party/absl/synchronization/mutex.h"
|
||||
#include "third_party/nearby_connections/cpp/platform/api/wifi_lan.h"
|
||||
#include "third_party/nearby_connections/cpp/platform/base/cancellation_flag.h"
|
||||
#include "third_party/nearby_connections/cpp/platform/base/exception.h"
|
||||
#include "third_party/nearby_connections/cpp/platform/base/nsd_service_info.h"
|
||||
#include "third_party/nearby_connections/cpp/platform/base/prng.h"
|
||||
#import "third_party/nearby_connections/cpp/platform/impl/ios/Source/Mediums/GNCMConnection.h"
|
||||
#import "third_party/nearby_connections/cpp/platform/impl/ios/Source/Mediums/WifiLan/GNCMBonjourBrowser.h"
|
||||
#import "third_party/nearby_connections/cpp/platform/impl/ios/Source/Mediums/WifiLan/GNCMBonjourService.h"
|
||||
#include "third_party/nearby_connections/cpp/platform/impl/ios/Source/Platform/utils.h"
|
||||
#import "third_party/objective_c/google_toolbox_for_mac/Foundation/GTMLogger.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace ios {
|
||||
|
||||
/** WifiLanInputStream implementation. */
|
||||
WifiLanInputStream::WifiLanInputStream()
|
||||
: newDataPackets_([NSMutableArray array]),
|
||||
accumulatedData_([NSMutableData data]),
|
||||
condition_([[NSCondition alloc] init]) {
|
||||
// Create the handlers of incoming data from the remote endpoint.
|
||||
connectionHandlers_ = [GNCMConnectionHandlers
|
||||
payloadHandler:^(NSData* data) {
|
||||
[condition_ lock];
|
||||
// Add the incoming data to the data packet array to be processed in Read() below.
|
||||
[newDataPackets_ addObject:data];
|
||||
[condition_ signal];
|
||||
[condition_ unlock];
|
||||
}
|
||||
disconnectedHandler:^{
|
||||
[condition_ lock];
|
||||
// Release the data packet array, meaning the stream has been closed or severed.
|
||||
newDataPackets_ = nil;
|
||||
[condition_ signal];
|
||||
[condition_ unlock];
|
||||
}];
|
||||
}
|
||||
|
||||
WifiLanInputStream::~WifiLanInputStream() {
|
||||
NSCAssert(!newDataPackets_, @"WifiLanInputStream not closed before destruction");
|
||||
}
|
||||
|
||||
ExceptionOr<ByteArray> WifiLanInputStream::Read(std::int64_t size) {
|
||||
// Block until either (a) the connection has been closed, or (b) enough data to return.
|
||||
NSData* dataToReturn;
|
||||
[condition_ lock];
|
||||
while (true) {
|
||||
// Check if the stream has been closed or severed.
|
||||
if (!newDataPackets_) break;
|
||||
|
||||
if (newDataPackets_.count > 0) {
|
||||
// Add the packet data to the accumulated data.
|
||||
for (NSData* data in newDataPackets_) {
|
||||
if (data.length > 0) {
|
||||
[accumulatedData_ appendData:data];
|
||||
}
|
||||
}
|
||||
[newDataPackets_ removeAllObjects];
|
||||
}
|
||||
|
||||
if ((size == -1) && (accumulatedData_.length > 0)) {
|
||||
// Return all of the data.
|
||||
dataToReturn = accumulatedData_;
|
||||
accumulatedData_ = [NSMutableData data];
|
||||
break;
|
||||
} else if (accumulatedData_.length > 0) {
|
||||
// Return up to |size| bytes of the data.
|
||||
std::int64_t sizeToReturn = accumulatedData_.length < size ? accumulatedData_.length : size;
|
||||
NSRange range = NSMakeRange(0, (NSUInteger)sizeToReturn);
|
||||
dataToReturn = [accumulatedData_ subdataWithRange:range];
|
||||
[accumulatedData_ replaceBytesInRange:range withBytes:nil length:0];
|
||||
break;
|
||||
}
|
||||
|
||||
[condition_ wait];
|
||||
}
|
||||
[condition_ unlock];
|
||||
|
||||
if (dataToReturn) {
|
||||
GTMLoggerInfo(@"[NEARBY] Input stream: Received data of size: %lu",
|
||||
(unsigned long)dataToReturn.length);
|
||||
return ExceptionOr<ByteArray>(ByteArrayFromNSData(dataToReturn));
|
||||
} else {
|
||||
return ExceptionOr<ByteArray>{Exception::kIo};
|
||||
}
|
||||
}
|
||||
|
||||
Exception WifiLanInputStream::Close() {
|
||||
// Unblock pending read operation.
|
||||
[condition_ lock];
|
||||
newDataPackets_ = nil;
|
||||
[condition_ signal];
|
||||
[condition_ unlock];
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
/** WifiLanOutputStream implementation. */
|
||||
WifiLanOutputStream::~WifiLanOutputStream() {
|
||||
NSCAssert(!connection_, @"WifiLanOutputStream not closed before destruction");
|
||||
}
|
||||
|
||||
Exception WifiLanOutputStream::Write(const ByteArray& data) {
|
||||
[condition_ lock];
|
||||
GTMLoggerDebug(@"[NEARBY] Sending data of size: %lu",
|
||||
(unsigned long)NSDataFromByteArray(data).length);
|
||||
|
||||
NSMutableData* packet = [NSMutableData dataWithData:NSDataFromByteArray(data)];
|
||||
|
||||
// Send the data, blocking until the completion handler is called.
|
||||
__block GNCMPayloadResult sendResult = GNCMPayloadResultFailure;
|
||||
__block bool isComplete = NO;
|
||||
NSCondition* condition = condition_; // don't capture |this| in completion
|
||||
// Check if connection_ is nil, then just don't wait and return as failure.
|
||||
if (connection_ != nil) {
|
||||
[connection_ sendData:packet
|
||||
progressHandler:^(size_t count) {
|
||||
}
|
||||
completion:^(GNCMPayloadResult result) {
|
||||
// Make sure we haven't already reported completion before. This prevents a crash
|
||||
// where we try leaving a dispatch group more times than we entered it.
|
||||
// b/79095653.
|
||||
if (isComplete) {
|
||||
return;
|
||||
}
|
||||
isComplete = YES;
|
||||
sendResult = result;
|
||||
[condition lock];
|
||||
[condition signal];
|
||||
[condition unlock];
|
||||
}];
|
||||
[condition_ wait];
|
||||
[condition_ unlock];
|
||||
} else {
|
||||
sendResult = GNCMPayloadResultFailure;
|
||||
[condition_ unlock];
|
||||
}
|
||||
|
||||
if (sendResult == GNCMPayloadResultSuccess) {
|
||||
return {Exception::kSuccess};
|
||||
} else {
|
||||
return {Exception::kIo};
|
||||
}
|
||||
}
|
||||
|
||||
Exception WifiLanOutputStream::Flush() {
|
||||
// The Write() function block until the data is received by the remote endpoint, so there's
|
||||
// nothing to do here.
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
Exception WifiLanOutputStream::Close() {
|
||||
// Unblock pending write operation.
|
||||
[condition_ lock];
|
||||
connection_ = nil;
|
||||
[condition_ signal];
|
||||
[condition_ unlock];
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
/** WifiLanSocket implementation. */
|
||||
WifiLanSocket::WifiLanSocket(id<GNCMConnection> connection)
|
||||
: input_stream_(new WifiLanInputStream()),
|
||||
output_stream_(new WifiLanOutputStream(connection)) {}
|
||||
|
||||
WifiLanSocket::~WifiLanSocket() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
DoClose();
|
||||
}
|
||||
|
||||
bool WifiLanSocket::IsClosed() const {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return closed_;
|
||||
}
|
||||
|
||||
Exception WifiLanSocket::Close() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
DoClose();
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
void WifiLanSocket::DoClose() {
|
||||
if (!closed_) {
|
||||
input_stream_->Close();
|
||||
output_stream_->Close();
|
||||
closed_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** WifiLanServerSocket implementation. */
|
||||
std::string WifiLanServerSocket::GetName(const std::string& ip_address, int port) {
|
||||
std::string dot_delimited_string;
|
||||
if (!ip_address.empty()) {
|
||||
for (auto byte : ip_address) {
|
||||
if (!dot_delimited_string.empty()) absl::StrAppend(&dot_delimited_string, ".");
|
||||
absl::StrAppend(&dot_delimited_string, absl::StrFormat("%d", byte));
|
||||
}
|
||||
}
|
||||
std::string out = absl::StrCat(dot_delimited_string, ":", port);
|
||||
return out;
|
||||
}
|
||||
|
||||
WifiLanServerSocket::~WifiLanServerSocket() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
DoClose();
|
||||
}
|
||||
|
||||
std::unique_ptr<api::WifiLanSocket> WifiLanServerSocket::Accept() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
while (!closed_ && pending_sockets_.empty()) {
|
||||
cond_.Wait(&mutex_);
|
||||
}
|
||||
// Return early if closed.
|
||||
if (closed_) return {};
|
||||
|
||||
auto remote_socket = std::move(pending_sockets_.extract(pending_sockets_.begin()).value());
|
||||
return std::move(remote_socket);
|
||||
}
|
||||
|
||||
bool WifiLanServerSocket::Connect(std::unique_ptr<WifiLanSocket> socket) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
if (closed_) {
|
||||
return false;
|
||||
}
|
||||
// add client socket to the pending list
|
||||
pending_sockets_.insert(std::move(socket));
|
||||
cond_.SignalAll();
|
||||
if (closed_) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void WifiLanServerSocket::SetCloseNotifier(std::function<void()> notifier) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
close_notifier_ = std::move(notifier);
|
||||
}
|
||||
|
||||
Exception WifiLanServerSocket::Close() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return DoClose();
|
||||
}
|
||||
|
||||
Exception WifiLanServerSocket::DoClose() {
|
||||
bool should_notify = !closed_;
|
||||
closed_ = true;
|
||||
if (should_notify) {
|
||||
cond_.SignalAll();
|
||||
if (close_notifier_) {
|
||||
auto notifier = std::move(close_notifier_);
|
||||
mutex_.Unlock();
|
||||
// Notifier may contain calls to public API, and may cause deadlock, if
|
||||
// mutex_ is held during the call.
|
||||
notifier();
|
||||
mutex_.Lock();
|
||||
}
|
||||
}
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
/** WifiLanMedium implementation. */
|
||||
WifiLanMedium::~WifiLanMedium() {
|
||||
advertising_info_.Clear();
|
||||
discovering_info_.Clear();
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StartAdvertising(const NsdServiceInfo& nsd_service_info) {
|
||||
std::string service_type = nsd_service_info.GetServiceType();
|
||||
NSString* serviceType = ObjCStringFromCppString(service_type);
|
||||
{
|
||||
absl::MutexLock lock(&mutex_);
|
||||
if (advertising_info_.Existed(service_type)) {
|
||||
GTMLoggerInfo(@"[NEARBY] WifiLan StartAdvertising: Can't start advertising because "
|
||||
@"service_type=%@, has started already",
|
||||
serviceType);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve service name.
|
||||
NSString* serviceName = ObjCStringFromCppString(nsd_service_info.GetServiceName());
|
||||
// Retrieve TXTRecord and convert it to NSDictionary type.
|
||||
NSDictionary<NSString*, NSData*>* TXTRecordData =
|
||||
NSDictionaryFromCppTxtRecords(nsd_service_info.GetTxtRecords());
|
||||
// Get ip address and port to retrieve the server_socket, if not, then return nil.
|
||||
std::string ip_address = nsd_service_info.GetIPAddress();
|
||||
int port = nsd_service_info.GetPort();
|
||||
__block std::string socket_name = WifiLanServerSocket::GetName(ip_address, port);
|
||||
GNCMBonjourService* service = [[GNCMBonjourService alloc]
|
||||
initWithServiceName:serviceName
|
||||
serviceType:serviceType
|
||||
port:requesting_port_
|
||||
TXTRecordData:TXTRecordData
|
||||
endpointConnectedHandler:^GNCMConnectionHandlers*(id<GNCMConnection> connection) {
|
||||
auto item = server_sockets_.find(socket_name);
|
||||
WifiLanServerSocket* server_socket = item != server_sockets_.end() ? item->second : nullptr;
|
||||
if (!server_socket) {
|
||||
return nil;
|
||||
}
|
||||
auto socket = absl::make_unique<WifiLanSocket>(connection);
|
||||
GNCMConnectionHandlers* connectionHandlers =
|
||||
static_cast<WifiLanInputStream&>(socket->GetInputStream()).GetConnectionHandlers();
|
||||
server_socket->Connect(std::move(socket));
|
||||
return connectionHandlers;
|
||||
}];
|
||||
{
|
||||
absl::MutexLock lock(&mutex_);
|
||||
advertising_info_.Add(service_type, service);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StopAdvertising(const NsdServiceInfo& nsd_service_info) {
|
||||
std::string service_type = nsd_service_info.GetServiceType();
|
||||
{
|
||||
absl::MutexLock lock(&mutex_);
|
||||
if (!advertising_info_.Existed(service_type)) {
|
||||
GTMLoggerInfo(@"[NEARBY] WifiLan StopAdvertising: Can't stop advertising because we never "
|
||||
@"started advertising for service_type=%@",
|
||||
ObjCStringFromCppString(service_type));
|
||||
return false;
|
||||
}
|
||||
advertising_info_.Remove(service_type);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StartDiscovery(const std::string& service_type,
|
||||
DiscoveredServiceCallback callback) {
|
||||
NSString* serviceType = ObjCStringFromCppString(service_type);
|
||||
{
|
||||
absl::MutexLock lock(&mutex_);
|
||||
if (discovering_info_.Existed(service_type)) {
|
||||
GTMLoggerInfo(@"[NEARBY] WifiLan StartAdvertising: Can't start discovery because "
|
||||
@"service_type=%@, has started already",
|
||||
serviceType);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
GNCMBonjourBrowser* browser = [[GNCMBonjourBrowser alloc]
|
||||
initWithServiceType:serviceType
|
||||
endpointFoundHandler:^GNCMEndpointLostHandler(
|
||||
NSString* endpointId, NSString* serviceType, NSString* serviceName,
|
||||
NSDictionary<NSString*, NSData*>* _Nullable txtRecordData,
|
||||
GNCMConnectionRequester requestConnection) {
|
||||
__block NsdServiceInfo nsd_service_info = {};
|
||||
nsd_service_info.SetServiceName(CppStringFromObjCString(serviceName));
|
||||
nsd_service_info.SetServiceType(CppStringFromObjCString(serviceType));
|
||||
// Set TXTRecord converted from NSDictionary to hash map.
|
||||
if (txtRecordData != nil) {
|
||||
auto txt_records = AbslHashMapFromObjCTxtRecords(txtRecordData);
|
||||
nsd_service_info.SetTxtRecords(txt_records);
|
||||
}
|
||||
connection_requesters_.insert({CppStringFromObjCString(serviceType), requestConnection});
|
||||
callback.service_discovered_cb(nsd_service_info);
|
||||
return ^{
|
||||
callback.service_lost_cb(nsd_service_info);
|
||||
};
|
||||
}];
|
||||
{
|
||||
absl::MutexLock lock(&mutex_);
|
||||
discovering_info_.Add(service_type, browser);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StopDiscovery(const std::string& service_type) {
|
||||
{
|
||||
absl::MutexLock lock(&mutex_);
|
||||
if (!discovering_info_.Existed(service_type)) {
|
||||
GTMLoggerInfo(@"[NEARBY] WifiLan StopDiscovery: Can't stop discovering because "
|
||||
"we never started discovering.");
|
||||
return false;
|
||||
}
|
||||
discovering_info_.Remove(service_type);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<api::WifiLanSocket> WifiLanMedium::ConnectToService(
|
||||
const NsdServiceInfo& remote_service_info, CancellationFlag* cancellation_flag) {
|
||||
std::string service_type = remote_service_info.GetServiceType();
|
||||
GTMLoggerInfo(@"[NEARBY] WifiLan ConnectToService, service_type=%@",
|
||||
ObjCStringFromCppString(service_type));
|
||||
|
||||
GNCMConnectionRequester connection_requester = nil;
|
||||
{
|
||||
absl::MutexLock lock(&mutex_);
|
||||
const auto& it = connection_requesters_.find(service_type);
|
||||
if (it == connection_requesters_.end()) {
|
||||
return {};
|
||||
}
|
||||
connection_requester = it->second;
|
||||
}
|
||||
|
||||
dispatch_group_t group = dispatch_group_create();
|
||||
dispatch_group_enter(group);
|
||||
__block std::unique_ptr<WifiLanSocket> socket;
|
||||
if (connection_requester != nil) {
|
||||
if (cancellation_flag->Cancelled()) {
|
||||
GTMLoggerError(@"[NEARBY] WifiLan Connect: Has been cancelled: service_type=%@",
|
||||
ObjCStringFromCppString(service_type));
|
||||
dispatch_group_leave(group); // unblock
|
||||
return {};
|
||||
}
|
||||
|
||||
connection_requester(^(id<GNCMConnection> connection) {
|
||||
// If the connection wasn't successfully established, return a NULL socket.
|
||||
if (connection) {
|
||||
socket = absl::make_unique<WifiLanSocket>(connection);
|
||||
}
|
||||
|
||||
dispatch_group_leave(group); // unblock
|
||||
return socket != nullptr ? static_cast<WifiLanInputStream&>(socket->GetInputStream())
|
||||
.GetConnectionHandlers()
|
||||
: nullptr;
|
||||
});
|
||||
}
|
||||
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
|
||||
|
||||
return std::move(socket);
|
||||
}
|
||||
|
||||
std::unique_ptr<api::WifiLanSocket> WifiLanMedium::ConnectToService(
|
||||
const std::string& ip_address, int port, CancellationFlag* cancellation_flag) {
|
||||
// Not implemented.
|
||||
return {};
|
||||
}
|
||||
|
||||
std::unique_ptr<api::WifiLanServerSocket> WifiLanMedium::ListenForService(int port) {
|
||||
auto server_socket = std::make_unique<WifiLanServerSocket>();
|
||||
// The fake ip address and port need to be set here since they can't be retrieved before
|
||||
// StartAadvertising begins. Furthermore, NSNetService can't resolve ip address when finding
|
||||
// service. Try to fake them and make it socket name as a key of server_sockets_ which acts
|
||||
// the same socket binding.
|
||||
server_socket->SetIPAddress(GetFakeIPAddress());
|
||||
requesting_port_ = port;
|
||||
server_socket->SetPort(requesting_port_ == 0 ? GetFakePort() : requesting_port_);
|
||||
std::string socket_name =
|
||||
WifiLanServerSocket::GetName(server_socket->GetIPAddress(), server_socket->GetPort());
|
||||
server_socket->SetCloseNotifier([this, socket_name]() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
server_sockets_.erase(socket_name);
|
||||
});
|
||||
GTMLoggerInfo(@"[NEARBY] WifiLan Adding server socket, socket_name=%@",
|
||||
ObjCStringFromCppString(socket_name));
|
||||
absl::MutexLock lock(&mutex_);
|
||||
server_sockets_.insert({socket_name, server_socket.get()});
|
||||
return server_socket;
|
||||
}
|
||||
|
||||
std::string WifiLanMedium::GetFakeIPAddress() const {
|
||||
std::string ip_address;
|
||||
ip_address.resize(4);
|
||||
uint32_t raw_ip_addr = Prng().NextUint32();
|
||||
ip_address[0] = static_cast<char>(raw_ip_addr >> 24);
|
||||
ip_address[1] = static_cast<char>(raw_ip_addr >> 16);
|
||||
ip_address[2] = static_cast<char>(raw_ip_addr >> 8);
|
||||
ip_address[3] = static_cast<char>(raw_ip_addr >> 0);
|
||||
|
||||
return ip_address;
|
||||
}
|
||||
|
||||
int WifiLanMedium::GetFakePort() const {
|
||||
uint16_t port = Prng().NextUint32();
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
} // namespace ios
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
Reference in New Issue
Block a user