[NETD-BPF#1] Move libnetdutils to frameworks/libs/net/...
libnetdutils is referenced by netd.c and TrafficController.cpp, which are going to be mainlined. Therefore, move libnetdutils to a common place where both mainline module and platform code (Netd) can refer to. Bug: 202086915 Test: build; flash; cd system/netd; atest Ignore-AOSP-First: the netd change(same topic) would not automerge from aosp. No-Typo-Check: Clean code move with no other changes. BYPASS_INCLUSIVE_LANGUAGE_REASON=Clean code move with no other changes. Change-Id: I645bfe35f6543149c9a9f894cd4158d27a481abe
This commit is contained in:
65
staticlibs/netd/libnetdutils/Android.bp
Normal file
65
staticlibs/netd/libnetdutils/Android.bp
Normal file
@@ -0,0 +1,65 @@
|
||||
package {
|
||||
default_applicable_licenses: ["Android-Apache-2.0"],
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "libnetdutils",
|
||||
srcs: [
|
||||
"DumpWriter.cpp",
|
||||
"Fd.cpp",
|
||||
"InternetAddresses.cpp",
|
||||
"Log.cpp",
|
||||
"Netfilter.cpp",
|
||||
"Netlink.cpp",
|
||||
"Slice.cpp",
|
||||
"Socket.cpp",
|
||||
"SocketOption.cpp",
|
||||
"Status.cpp",
|
||||
"Syscalls.cpp",
|
||||
"UniqueFd.cpp",
|
||||
"UniqueFile.cpp",
|
||||
],
|
||||
defaults: ["netd_defaults"],
|
||||
cflags: ["-Wall", "-Werror"],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"liblog",
|
||||
],
|
||||
export_shared_lib_headers: [
|
||||
"libbase",
|
||||
],
|
||||
export_include_dirs: ["include"],
|
||||
sanitize: {
|
||||
cfi: true,
|
||||
},
|
||||
|
||||
apex_available: [
|
||||
"//apex_available:platform",
|
||||
"com.android.resolv",
|
||||
],
|
||||
min_sdk_version: "29",
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "netdutils_test",
|
||||
srcs: [
|
||||
"BackoffSequenceTest.cpp",
|
||||
"FdTest.cpp",
|
||||
"InternetAddressesTest.cpp",
|
||||
"LogTest.cpp",
|
||||
"MemBlockTest.cpp",
|
||||
"SliceTest.cpp",
|
||||
"StatusTest.cpp",
|
||||
"SyscallsTest.cpp",
|
||||
"ThreadUtilTest.cpp",
|
||||
],
|
||||
defaults: ["netd_defaults"],
|
||||
test_suites: ["device-tests"],
|
||||
static_libs: [
|
||||
"libgmock",
|
||||
"libnetdutils",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
],
|
||||
}
|
||||
186
staticlibs/netd/libnetdutils/BackoffSequenceTest.cpp
Normal file
186
staticlibs/netd/libnetdutils/BackoffSequenceTest.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 <gtest/gtest.h>
|
||||
|
||||
#include "netdutils/BackoffSequence.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
TEST(BackoffSequence, defaults) {
|
||||
BackoffSequence<uint32_t> backoff;
|
||||
|
||||
EXPECT_TRUE(backoff.hasNextTimeout());
|
||||
EXPECT_EQ(0x00000001U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000002U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000004U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000008U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000010U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000020U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000040U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000080U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000100U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000200U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000400U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000800U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00001000U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00002000U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00004000U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00008000U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00010000U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00020000U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00040000U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00080000U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00100000U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00200000U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00400000U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00800000U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x01000000U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x02000000U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x04000000U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x08000000U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x10000000U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x20000000U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x40000000U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x80000000U, backoff.getNextTimeout());
|
||||
// Maxes out, and stays there, ad infinitum.
|
||||
for (int i = 0; i < 10; i++) {
|
||||
EXPECT_TRUE(backoff.hasNextTimeout());
|
||||
EXPECT_EQ(0xffffffffU, backoff.getNextTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BackoffSequence, backoffToOncePerHour) {
|
||||
auto backoff = BackoffSequence<uint32_t>::Builder()
|
||||
.withInitialRetransmissionTime(1)
|
||||
.withMaximumRetransmissionTime(3600)
|
||||
.build();
|
||||
|
||||
EXPECT_TRUE(backoff.hasNextTimeout());
|
||||
EXPECT_EQ(0x00000001U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000002U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000004U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000008U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000010U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000020U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000040U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000080U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000100U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000200U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000400U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000800U, backoff.getNextTimeout());
|
||||
// Maxes out, and stays there, ad infinitum.
|
||||
for (int i = 0; i < 10; i++) {
|
||||
EXPECT_TRUE(backoff.hasNextTimeout());
|
||||
EXPECT_EQ(3600U, backoff.getNextTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BackoffSequence, simpleMaxRetransCount) {
|
||||
auto backoff = BackoffSequence<uint32_t>::Builder()
|
||||
.withInitialRetransmissionTime(3)
|
||||
.withMaximumRetransmissionCount(7)
|
||||
.build();
|
||||
|
||||
EXPECT_TRUE(backoff.hasNextTimeout());
|
||||
EXPECT_EQ(0x00000003U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000006U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x0000000cU, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000018U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000030U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000060U, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x000000c0U, backoff.getNextTimeout());
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
EXPECT_FALSE(backoff.hasNextTimeout());
|
||||
EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BackoffSequence, simpleMaxDuration) {
|
||||
auto backoff = BackoffSequence<int>::Builder()
|
||||
.withInitialRetransmissionTime(3)
|
||||
.withMaximumRetransmissionDuration(7)
|
||||
.withEndOfSequenceIndicator(-1)
|
||||
.build();
|
||||
|
||||
EXPECT_TRUE(backoff.hasNextTimeout());
|
||||
EXPECT_EQ(0x00000003, backoff.getNextTimeout());
|
||||
EXPECT_EQ(0x00000004, backoff.getNextTimeout());
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
EXPECT_FALSE(backoff.hasNextTimeout());
|
||||
EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout());
|
||||
EXPECT_EQ(-1, backoff.getNextTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PathologicalBackoffSequence, ZeroInitialRetransTime) {
|
||||
auto backoff = BackoffSequence<std::chrono::seconds>::Builder()
|
||||
.withInitialRetransmissionTime(std::chrono::seconds(0))
|
||||
.build();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
// TODO: Decide whether this needs fixing, and how.
|
||||
EXPECT_TRUE(backoff.hasNextTimeout());
|
||||
EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PathologicalBackoffSequence, MaxRetransDurationGreaterThanInitialRetransTime) {
|
||||
auto backoff = BackoffSequence<std::chrono::milliseconds>::Builder()
|
||||
.withInitialRetransmissionTime(std::chrono::milliseconds(5))
|
||||
.withMaximumRetransmissionDuration(std::chrono::milliseconds(3))
|
||||
.build();
|
||||
|
||||
EXPECT_EQ(std::chrono::milliseconds(3), backoff.getNextTimeout());
|
||||
for (int i = 0; i < 10; i++) {
|
||||
EXPECT_FALSE(backoff.hasNextTimeout());
|
||||
EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PathologicalBackoffSequence, MaxRetransDurationEqualsInitialRetransTime) {
|
||||
auto backoff = BackoffSequence<std::chrono::hours>::Builder()
|
||||
.withInitialRetransmissionTime(std::chrono::hours(5))
|
||||
.withMaximumRetransmissionDuration(std::chrono::hours(5))
|
||||
.build();
|
||||
|
||||
EXPECT_EQ(std::chrono::hours(5), backoff.getNextTimeout());
|
||||
for (int i = 0; i < 10; i++) {
|
||||
EXPECT_FALSE(backoff.hasNextTimeout());
|
||||
EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PathologicalBackoffSequence, MaxRetransTimeAndDurationGreaterThanInitialRetransTime) {
|
||||
auto backoff = BackoffSequence<std::chrono::nanoseconds>::Builder()
|
||||
.withInitialRetransmissionTime(std::chrono::nanoseconds(7))
|
||||
.withMaximumRetransmissionTime(std::chrono::nanoseconds(3))
|
||||
.withMaximumRetransmissionDuration(std::chrono::nanoseconds(5))
|
||||
.build();
|
||||
|
||||
EXPECT_EQ(std::chrono::nanoseconds(3), backoff.getNextTimeout());
|
||||
EXPECT_EQ(std::chrono::nanoseconds(2), backoff.getNextTimeout());
|
||||
for (int i = 0; i < 10; i++) {
|
||||
EXPECT_FALSE(backoff.hasNextTimeout());
|
||||
EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
72
staticlibs/netd/libnetdutils/DumpWriter.cpp
Normal file
72
staticlibs/netd/libnetdutils/DumpWriter.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 "netdutils/DumpWriter.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <limits>
|
||||
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <utils/String8.h>
|
||||
|
||||
using android::base::StringAppendV;
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
namespace {
|
||||
|
||||
const char kIndentString[] = " ";
|
||||
const size_t kIndentStringLen = strlen(kIndentString);
|
||||
|
||||
} // namespace
|
||||
|
||||
DumpWriter::DumpWriter(int fd) : mIndentLevel(0), mFd(fd) {}
|
||||
|
||||
void DumpWriter::incIndent() {
|
||||
if (mIndentLevel < std::numeric_limits<decltype(mIndentLevel)>::max()) {
|
||||
mIndentLevel++;
|
||||
}
|
||||
}
|
||||
|
||||
void DumpWriter::decIndent() {
|
||||
if (mIndentLevel > std::numeric_limits<decltype(mIndentLevel)>::min()) {
|
||||
mIndentLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
void DumpWriter::println(const std::string& line) {
|
||||
if (!line.empty()) {
|
||||
for (int i = 0; i < mIndentLevel; i++) {
|
||||
::write(mFd, kIndentString, kIndentStringLen);
|
||||
}
|
||||
::write(mFd, line.c_str(), line.size());
|
||||
}
|
||||
::write(mFd, "\n", 1);
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(cert-dcl50-cpp): Grandfathered C-style variadic function.
|
||||
void DumpWriter::println(const char* fmt, ...) {
|
||||
std::string line;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
StringAppendV(&line, fmt, ap);
|
||||
va_end(ap);
|
||||
println(line);
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
27
staticlibs/netd/libnetdutils/Fd.cpp
Normal file
27
staticlibs/netd/libnetdutils/Fd.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 "netdutils/Fd.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Fd& fd) {
|
||||
return os << "Fd[" << fd.get() << "]";
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
147
staticlibs/netd/libnetdutils/FdTest.cpp
Normal file
147
staticlibs/netd/libnetdutils/FdTest.cpp
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 <cstdint>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "netdutils/MockSyscalls.h"
|
||||
#include "netdutils/Status.h"
|
||||
#include "netdutils/Syscalls.h"
|
||||
|
||||
using testing::Mock;
|
||||
using testing::Return;
|
||||
using testing::StrictMock;
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
namespace {
|
||||
|
||||
// Force implicit conversion from UniqueFd -> Fd
|
||||
inline Fd toFd(const UniqueFd& fd) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(Fd, smoke) {
|
||||
// Expect the following lines to compile
|
||||
Fd fd1(1);
|
||||
Fd fd2(fd1);
|
||||
Fd fd3 = fd2;
|
||||
const Fd fd4(8);
|
||||
const Fd fd5(fd4);
|
||||
const Fd fd6 = fd5;
|
||||
EXPECT_TRUE(isWellFormed(fd3));
|
||||
EXPECT_TRUE(isWellFormed(fd6));
|
||||
|
||||
// Corner case
|
||||
Fd zero(0);
|
||||
EXPECT_TRUE(isWellFormed(zero));
|
||||
|
||||
// Invalid file descriptors
|
||||
Fd bad(-1);
|
||||
Fd weird(-9);
|
||||
EXPECT_FALSE(isWellFormed(bad));
|
||||
EXPECT_FALSE(isWellFormed(weird));
|
||||
|
||||
// Default constructor
|
||||
EXPECT_EQ(Fd(-1), Fd());
|
||||
std::stringstream ss;
|
||||
ss << fd3 << " " << fd6 << " " << bad << " " << weird;
|
||||
EXPECT_EQ("Fd[1] Fd[8] Fd[-1] Fd[-9]", ss.str());
|
||||
}
|
||||
|
||||
class UniqueFdTest : public testing::Test {
|
||||
protected:
|
||||
StrictMock<ScopedMockSyscalls> mSyscalls;
|
||||
};
|
||||
|
||||
TEST_F(UniqueFdTest, operatorOstream) {
|
||||
UniqueFd u(97);
|
||||
EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(status::ok));
|
||||
std::stringstream ss;
|
||||
ss << u;
|
||||
EXPECT_EQ("UniqueFd[Fd[97]]", ss.str());
|
||||
u.reset();
|
||||
}
|
||||
|
||||
TEST_F(UniqueFdTest, destructor) {
|
||||
{
|
||||
UniqueFd u(98);
|
||||
EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(status::ok));
|
||||
}
|
||||
// Expectation above should be upon leaving nested scope
|
||||
Mock::VerifyAndClearExpectations(&mSyscalls);
|
||||
}
|
||||
|
||||
TEST_F(UniqueFdTest, reset) {
|
||||
UniqueFd u(99);
|
||||
EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(status::ok));
|
||||
u.reset();
|
||||
|
||||
// Expectation above should be upon reset
|
||||
Mock::VerifyAndClearExpectations(&mSyscalls);
|
||||
}
|
||||
|
||||
TEST_F(UniqueFdTest, moveConstructor) {
|
||||
constexpr Fd kFd(101);
|
||||
UniqueFd u1(kFd);
|
||||
{
|
||||
UniqueFd u2(std::move(u1));
|
||||
// NOLINTNEXTLINE bugprone-use-after-move
|
||||
EXPECT_FALSE(isWellFormed(u1));
|
||||
EXPECT_TRUE(isWellFormed(u2));
|
||||
EXPECT_CALL(mSyscalls, close(kFd)).WillOnce(Return(status::ok));
|
||||
}
|
||||
// Expectation above should be upon leaving nested scope
|
||||
Mock::VerifyAndClearExpectations(&mSyscalls);
|
||||
}
|
||||
|
||||
TEST_F(UniqueFdTest, moveAssignment) {
|
||||
constexpr Fd kFd(102);
|
||||
UniqueFd u1(kFd);
|
||||
{
|
||||
UniqueFd u2 = std::move(u1);
|
||||
// NOLINTNEXTLINE bugprone-use-after-move
|
||||
EXPECT_FALSE(isWellFormed(u1));
|
||||
EXPECT_TRUE(isWellFormed(u2));
|
||||
UniqueFd u3;
|
||||
u3 = std::move(u2);
|
||||
// NOLINTNEXTLINE bugprone-use-after-move
|
||||
EXPECT_FALSE(isWellFormed(u2));
|
||||
EXPECT_TRUE(isWellFormed(u3));
|
||||
EXPECT_CALL(mSyscalls, close(kFd)).WillOnce(Return(status::ok));
|
||||
}
|
||||
// Expectation above should be upon leaving nested scope
|
||||
Mock::VerifyAndClearExpectations(&mSyscalls);
|
||||
}
|
||||
|
||||
TEST_F(UniqueFdTest, constConstructor) {
|
||||
constexpr Fd kFd(103);
|
||||
const UniqueFd u(kFd);
|
||||
EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(status::ok));
|
||||
}
|
||||
|
||||
TEST_F(UniqueFdTest, closeFailure) {
|
||||
constexpr Fd kFd(103);
|
||||
UniqueFd u(kFd);
|
||||
EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(statusFromErrno(EINTR, "test")));
|
||||
EXPECT_DEBUG_DEATH(u.reset(), "");
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
164
staticlibs/netd/libnetdutils/InternetAddresses.cpp
Normal file
164
staticlibs/netd/libnetdutils/InternetAddresses.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 "netdutils/InternetAddresses.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
using base::StringPrintf;
|
||||
|
||||
namespace netdutils {
|
||||
|
||||
std::string IPAddress::toString() const noexcept {
|
||||
char repr[INET6_ADDRSTRLEN] = "\0";
|
||||
|
||||
switch (mData.family) {
|
||||
case AF_UNSPEC:
|
||||
return "<unspecified>";
|
||||
case AF_INET: {
|
||||
const in_addr v4 = mData.ip.v4;
|
||||
inet_ntop(AF_INET, &v4, repr, sizeof(repr));
|
||||
break;
|
||||
}
|
||||
case AF_INET6: {
|
||||
const in6_addr v6 = mData.ip.v6;
|
||||
inet_ntop(AF_INET6, &v6, repr, sizeof(repr));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return "<unknown_family>";
|
||||
}
|
||||
|
||||
if (mData.family == AF_INET6 && mData.scope_id > 0) {
|
||||
return StringPrintf("%s%%%u", repr, mData.scope_id);
|
||||
}
|
||||
|
||||
return repr;
|
||||
}
|
||||
|
||||
bool IPAddress::forString(const std::string& repr, IPAddress* ip) {
|
||||
const addrinfo hints = {
|
||||
.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV,
|
||||
};
|
||||
addrinfo* res;
|
||||
const int ret = getaddrinfo(repr.c_str(), nullptr, &hints, &res);
|
||||
ScopedAddrinfo res_cleanup(res);
|
||||
if (ret != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool rval = true;
|
||||
switch (res[0].ai_family) {
|
||||
case AF_INET: {
|
||||
sockaddr_in* sin = (sockaddr_in*) res[0].ai_addr;
|
||||
if (ip) *ip = IPAddress(sin->sin_addr);
|
||||
break;
|
||||
}
|
||||
case AF_INET6: {
|
||||
sockaddr_in6* sin6 = (sockaddr_in6*) res[0].ai_addr;
|
||||
if (ip) *ip = IPAddress(sin6->sin6_addr, sin6->sin6_scope_id);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
rval = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
IPPrefix::IPPrefix(const IPAddress& ip, int length) : IPPrefix(ip) {
|
||||
// Silently treat CIDR lengths like "-1" as meaning the full bit length
|
||||
// appropriate to the address family.
|
||||
if (length < 0) return;
|
||||
if (length >= mData.cidrlen) return;
|
||||
|
||||
switch (mData.family) {
|
||||
case AF_UNSPEC:
|
||||
break;
|
||||
case AF_INET: {
|
||||
const in_addr_t mask = (length > 0) ? (~0U) << (IPV4_ADDR_BITS - length) : 0U;
|
||||
mData.ip.v4.s_addr &= htonl(mask);
|
||||
mData.cidrlen = static_cast<uint8_t>(length);
|
||||
break;
|
||||
}
|
||||
case AF_INET6: {
|
||||
// The byte in which this CIDR length falls.
|
||||
const int which = length / 8;
|
||||
const int mask = (length % 8 == 0) ? 0 : 0xff << (8 - length % 8);
|
||||
mData.ip.v6.s6_addr[which] &= mask;
|
||||
for (int i = which + 1; i < IPV6_ADDR_LEN; i++) {
|
||||
mData.ip.v6.s6_addr[i] = 0U;
|
||||
}
|
||||
mData.cidrlen = static_cast<uint8_t>(length);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// TODO: Complain bitterly about possible data corruption?
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool IPPrefix::isUninitialized() const noexcept {
|
||||
static const internal_::compact_ipdata empty{};
|
||||
return mData == empty;
|
||||
}
|
||||
|
||||
bool IPPrefix::forString(const std::string& repr, IPPrefix* prefix) {
|
||||
size_t index = repr.find('/');
|
||||
if (index == std::string::npos) return false;
|
||||
|
||||
// Parse the IP address.
|
||||
IPAddress ip;
|
||||
if (!IPAddress::forString(repr.substr(0, index), &ip)) return false;
|
||||
|
||||
// Parse the prefix length. Can't use base::ParseUint because it accepts non-base 10 input.
|
||||
const char* prefixString = repr.c_str() + index + 1;
|
||||
if (!isdigit(*prefixString)) return false;
|
||||
char* endptr;
|
||||
unsigned long prefixlen = strtoul(prefixString, &endptr, 10);
|
||||
if (*endptr != '\0') return false;
|
||||
|
||||
uint8_t maxlen = (ip.family() == AF_INET) ? 32 : 128;
|
||||
if (prefixlen > maxlen) return false;
|
||||
|
||||
*prefix = IPPrefix(ip, prefixlen);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string IPPrefix::toString() const noexcept {
|
||||
return StringPrintf("%s/%d", ip().toString().c_str(), mData.cidrlen);
|
||||
}
|
||||
|
||||
std::string IPSockAddr::toString() const noexcept {
|
||||
switch (mData.family) {
|
||||
case AF_INET6:
|
||||
return StringPrintf("[%s]:%u", ip().toString().c_str(), mData.port);
|
||||
default:
|
||||
return StringPrintf("%s:%u", ip().toString().c_str(), mData.port);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
541
staticlibs/netd/libnetdutils/InternetAddressesTest.cpp
Normal file
541
staticlibs/netd/libnetdutils/InternetAddressesTest.cpp
Normal file
@@ -0,0 +1,541 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 <cstdint>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/macros.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "netdutils/InternetAddresses.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
namespace {
|
||||
|
||||
enum Relation { EQ, LT };
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, Relation relation) {
|
||||
switch (relation) {
|
||||
case EQ: os << "eq"; break;
|
||||
case LT: os << "lt"; break;
|
||||
default: os << "?!"; break;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct OperatorExpectation {
|
||||
const Relation relation;
|
||||
const T obj1;
|
||||
const T obj2;
|
||||
|
||||
std::string toString() const {
|
||||
std::stringstream output;
|
||||
output << obj1 << " " << relation << " " << obj2;
|
||||
return output.str();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void testGamutOfOperators(const OperatorExpectation<T>& expectation) {
|
||||
switch (expectation.relation) {
|
||||
case EQ:
|
||||
EXPECT_TRUE(expectation.obj1 == expectation.obj2);
|
||||
EXPECT_TRUE(expectation.obj1 <= expectation.obj2);
|
||||
EXPECT_TRUE(expectation.obj1 >= expectation.obj2);
|
||||
EXPECT_FALSE(expectation.obj1 != expectation.obj2);
|
||||
EXPECT_FALSE(expectation.obj1 < expectation.obj2);
|
||||
EXPECT_FALSE(expectation.obj1 > expectation.obj2);
|
||||
break;
|
||||
|
||||
case LT:
|
||||
EXPECT_TRUE(expectation.obj1 < expectation.obj2);
|
||||
EXPECT_TRUE(expectation.obj1 <= expectation.obj2);
|
||||
EXPECT_TRUE(expectation.obj1 != expectation.obj2);
|
||||
EXPECT_FALSE(expectation.obj1 > expectation.obj2);
|
||||
EXPECT_FALSE(expectation.obj1 >= expectation.obj2);
|
||||
EXPECT_FALSE(expectation.obj1 == expectation.obj2);
|
||||
break;
|
||||
|
||||
default:
|
||||
FAIL() << "Unknown relation given in test expectation";
|
||||
}
|
||||
}
|
||||
|
||||
const in_addr IPV4_ANY{htonl(INADDR_ANY)};
|
||||
const in_addr IPV4_LOOPBACK{htonl(INADDR_LOOPBACK)};
|
||||
const in_addr IPV4_ONES{~0U};
|
||||
const in6_addr IPV6_ANY = IN6ADDR_ANY_INIT;
|
||||
const in6_addr IPV6_LOOPBACK = IN6ADDR_LOOPBACK_INIT;
|
||||
const in6_addr FE80{{{0xfe,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}};
|
||||
const in6_addr FE80_1{{{0xfe,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,1}}};
|
||||
const in6_addr FE80_2{{{0xfe,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,2}}};
|
||||
const uint8_t ff = std::numeric_limits<uint8_t>::max();
|
||||
const in6_addr IPV6_ONES{{{ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff}}};
|
||||
|
||||
TEST(IPAddressTest, GamutOfOperators) {
|
||||
const std::vector<OperatorExpectation<IPAddress>> kExpectations{
|
||||
{EQ, IPAddress(), IPAddress()},
|
||||
{EQ, IPAddress(IPV4_ONES), IPAddress(IPV4_ONES)},
|
||||
{EQ, IPAddress(IPV6_ONES), IPAddress(IPV6_ONES)},
|
||||
{EQ, IPAddress(FE80_1), IPAddress(FE80_1)},
|
||||
{EQ, IPAddress(FE80_2), IPAddress(FE80_2)},
|
||||
{LT, IPAddress(), IPAddress(IPV4_ANY)},
|
||||
{LT, IPAddress(), IPAddress(IPV4_ONES)},
|
||||
{LT, IPAddress(), IPAddress(IPV6_ANY)},
|
||||
{LT, IPAddress(), IPAddress(IPV6_ONES)},
|
||||
{LT, IPAddress(IPV4_ANY), IPAddress(IPV4_ONES)},
|
||||
{LT, IPAddress(IPV4_ANY), IPAddress(IPV6_ANY)},
|
||||
{LT, IPAddress(IPV4_ONES), IPAddress(IPV6_ANY)},
|
||||
{LT, IPAddress(IPV4_ONES), IPAddress(IPV6_ONES)},
|
||||
{LT, IPAddress(IPV6_ANY), IPAddress(IPV6_LOOPBACK)},
|
||||
{LT, IPAddress(IPV6_ANY), IPAddress(IPV6_ONES)},
|
||||
{LT, IPAddress(IPV6_LOOPBACK), IPAddress(IPV6_ONES)},
|
||||
{LT, IPAddress(FE80_1), IPAddress(FE80_2)},
|
||||
{LT, IPAddress(FE80_1), IPAddress(IPV6_ONES)},
|
||||
{LT, IPAddress(FE80_2), IPAddress(IPV6_ONES)},
|
||||
// Sort by scoped_id within the same address.
|
||||
{LT, IPAddress(FE80_1), IPAddress(FE80_1, 1)},
|
||||
{LT, IPAddress(FE80_1, 1), IPAddress(FE80_1, 2)},
|
||||
// Sort by address first, scope_id second.
|
||||
{LT, IPAddress(FE80_1, 2), IPAddress(FE80_2, 1)},
|
||||
};
|
||||
|
||||
size_t tests_run = 0;
|
||||
for (const auto& expectation : kExpectations) {
|
||||
SCOPED_TRACE(expectation.toString());
|
||||
EXPECT_NO_FATAL_FAILURE(testGamutOfOperators(expectation));
|
||||
tests_run++;
|
||||
}
|
||||
EXPECT_EQ(kExpectations.size(), tests_run);
|
||||
}
|
||||
|
||||
TEST(IPAddressTest, ScopeIds) {
|
||||
// Scope IDs ignored for IPv4 addresses.
|
||||
const IPAddress ones(IPV4_ONES);
|
||||
EXPECT_EQ(0U, ones.scope_id());
|
||||
const IPAddress ones22(ones, 22);
|
||||
EXPECT_EQ(0U, ones22.scope_id());
|
||||
EXPECT_EQ(ones, ones22);
|
||||
const IPAddress ones23(ones, 23);
|
||||
EXPECT_EQ(0U, ones23.scope_id());
|
||||
EXPECT_EQ(ones22, ones23);
|
||||
|
||||
EXPECT_EQ("fe80::1%22", IPAddress(FE80_1, 22).toString());
|
||||
EXPECT_EQ("fe80::2%23", IPAddress(FE80_2, 23).toString());
|
||||
|
||||
// Verify that given an IPAddress with a scope_id an address without a
|
||||
// scope_id can be constructed (just in case it's useful).
|
||||
const IPAddress fe80_intf22(FE80_1, 22);
|
||||
EXPECT_EQ(22U, fe80_intf22.scope_id());
|
||||
EXPECT_EQ(fe80_intf22, IPAddress(fe80_intf22));
|
||||
EXPECT_EQ(IPAddress(FE80_1), IPAddress(fe80_intf22, 0));
|
||||
}
|
||||
|
||||
TEST(IPAddressTest, forString) {
|
||||
IPAddress ip;
|
||||
|
||||
EXPECT_FALSE(IPAddress::forString("not_an_ip", &ip));
|
||||
EXPECT_FALSE(IPAddress::forString("not_an_ip", nullptr));
|
||||
EXPECT_EQ(IPAddress(), IPAddress::forString("not_an_ip"));
|
||||
|
||||
EXPECT_EQ(IPAddress(IPV4_ANY), IPAddress::forString("0.0.0.0"));
|
||||
EXPECT_EQ(IPAddress(IPV4_ONES), IPAddress::forString("255.255.255.255"));
|
||||
EXPECT_EQ(IPAddress(IPV4_LOOPBACK), IPAddress::forString("127.0.0.1"));
|
||||
|
||||
EXPECT_EQ(IPAddress(IPV6_ANY), IPAddress::forString("::"));
|
||||
EXPECT_EQ(IPAddress(IPV6_ANY), IPAddress::forString("::0"));
|
||||
EXPECT_EQ(IPAddress(IPV6_ANY), IPAddress::forString("0::"));
|
||||
EXPECT_EQ(IPAddress(IPV6_LOOPBACK), IPAddress::forString("::1"));
|
||||
EXPECT_EQ(IPAddress(IPV6_LOOPBACK), IPAddress::forString("0::1"));
|
||||
EXPECT_EQ(IPAddress(FE80_1), IPAddress::forString("fe80::1"));
|
||||
EXPECT_EQ(IPAddress(FE80_1, 22), IPAddress::forString("fe80::1%22"));
|
||||
// This relies upon having a loopback interface named "lo" with ifindex 1.
|
||||
EXPECT_EQ(IPAddress(FE80_1, 1), IPAddress::forString("fe80::1%lo"));
|
||||
}
|
||||
|
||||
TEST(IPPrefixTest, forString) {
|
||||
IPPrefix prefix;
|
||||
|
||||
EXPECT_FALSE(IPPrefix::forString("", &prefix));
|
||||
EXPECT_FALSE(IPPrefix::forString("invalid", &prefix));
|
||||
EXPECT_FALSE(IPPrefix::forString("192.0.2.0", &prefix));
|
||||
EXPECT_FALSE(IPPrefix::forString("2001::db8::", &prefix));
|
||||
|
||||
EXPECT_FALSE(IPPrefix::forString("2001:db8::/", &prefix));
|
||||
EXPECT_FALSE(IPPrefix::forString("2001:db8:://32", &prefix));
|
||||
EXPECT_FALSE(IPPrefix::forString("2001:db8::/32z", &prefix));
|
||||
EXPECT_FALSE(IPPrefix::forString("2001:db8::/32/", &prefix));
|
||||
EXPECT_FALSE(IPPrefix::forString("2001:db8::/0x20", &prefix));
|
||||
EXPECT_FALSE(IPPrefix::forString("2001:db8:: /32", &prefix));
|
||||
EXPECT_FALSE(IPPrefix::forString("2001:db8::/ 32", &prefix));
|
||||
EXPECT_FALSE(IPPrefix::forString(" 2001:db8::/32", &prefix));
|
||||
EXPECT_FALSE(IPPrefix::forString("2001:db8::/32 ", &prefix));
|
||||
EXPECT_FALSE(IPPrefix::forString("2001:db8::/+32", &prefix));
|
||||
|
||||
EXPECT_FALSE(IPPrefix::forString("192.0.2.0/33", &prefix));
|
||||
EXPECT_FALSE(IPPrefix::forString("2001:db8::/129", &prefix));
|
||||
EXPECT_FALSE(IPPrefix::forString("192.0.2.0/-1", &prefix));
|
||||
EXPECT_FALSE(IPPrefix::forString("2001:db8::/-1", &prefix));
|
||||
|
||||
EXPECT_TRUE(IPPrefix::forString("2001:db8::/32", &prefix));
|
||||
EXPECT_EQ("2001:db8::/32", prefix.toString());
|
||||
EXPECT_EQ(IPPrefix(IPAddress::forString("2001:db8::"), 32), prefix);
|
||||
|
||||
EXPECT_EQ(IPPrefix(), IPPrefix::forString("invalid"));
|
||||
|
||||
EXPECT_EQ("0.0.0.0/0", IPPrefix::forString("0.0.0.0/0").toString());
|
||||
EXPECT_EQ("::/0", IPPrefix::forString("::/0").toString());
|
||||
EXPECT_EQ("192.0.2.128/25", IPPrefix::forString("192.0.2.131/25").toString());
|
||||
EXPECT_EQ("2001:db8:1:2:3:4:5:4/126",
|
||||
IPPrefix::forString("2001:db8:1:2:3:4:5:6/126").toString());
|
||||
}
|
||||
|
||||
TEST(IPPrefixTest, IPv4Truncation) {
|
||||
const auto prefixStr = [](int length) -> std::string {
|
||||
return IPPrefix(IPAddress(IPV4_ONES), length).toString();
|
||||
};
|
||||
|
||||
EXPECT_EQ("0.0.0.0/0", prefixStr(0));
|
||||
|
||||
EXPECT_EQ("128.0.0.0/1", prefixStr(1));
|
||||
EXPECT_EQ("192.0.0.0/2", prefixStr(2));
|
||||
EXPECT_EQ("224.0.0.0/3", prefixStr(3));
|
||||
EXPECT_EQ("240.0.0.0/4", prefixStr(4));
|
||||
EXPECT_EQ("248.0.0.0/5", prefixStr(5));
|
||||
EXPECT_EQ("252.0.0.0/6", prefixStr(6));
|
||||
EXPECT_EQ("254.0.0.0/7", prefixStr(7));
|
||||
EXPECT_EQ("255.0.0.0/8", prefixStr(8));
|
||||
|
||||
EXPECT_EQ("255.128.0.0/9", prefixStr(9));
|
||||
EXPECT_EQ("255.192.0.0/10", prefixStr(10));
|
||||
EXPECT_EQ("255.224.0.0/11", prefixStr(11));
|
||||
EXPECT_EQ("255.240.0.0/12", prefixStr(12));
|
||||
EXPECT_EQ("255.248.0.0/13", prefixStr(13));
|
||||
EXPECT_EQ("255.252.0.0/14", prefixStr(14));
|
||||
EXPECT_EQ("255.254.0.0/15", prefixStr(15));
|
||||
EXPECT_EQ("255.255.0.0/16", prefixStr(16));
|
||||
|
||||
EXPECT_EQ("255.255.128.0/17", prefixStr(17));
|
||||
EXPECT_EQ("255.255.192.0/18", prefixStr(18));
|
||||
EXPECT_EQ("255.255.224.0/19", prefixStr(19));
|
||||
EXPECT_EQ("255.255.240.0/20", prefixStr(20));
|
||||
EXPECT_EQ("255.255.248.0/21", prefixStr(21));
|
||||
EXPECT_EQ("255.255.252.0/22", prefixStr(22));
|
||||
EXPECT_EQ("255.255.254.0/23", prefixStr(23));
|
||||
EXPECT_EQ("255.255.255.0/24", prefixStr(24));
|
||||
|
||||
EXPECT_EQ("255.255.255.128/25", prefixStr(25));
|
||||
EXPECT_EQ("255.255.255.192/26", prefixStr(26));
|
||||
EXPECT_EQ("255.255.255.224/27", prefixStr(27));
|
||||
EXPECT_EQ("255.255.255.240/28", prefixStr(28));
|
||||
EXPECT_EQ("255.255.255.248/29", prefixStr(29));
|
||||
EXPECT_EQ("255.255.255.252/30", prefixStr(30));
|
||||
EXPECT_EQ("255.255.255.254/31", prefixStr(31));
|
||||
EXPECT_EQ("255.255.255.255/32", prefixStr(32));
|
||||
}
|
||||
|
||||
TEST(IPPrefixTest, IPv6Truncation) {
|
||||
const auto prefixStr = [](int length) -> std::string {
|
||||
return IPPrefix(IPAddress(IPV6_ONES), length).toString();
|
||||
};
|
||||
|
||||
EXPECT_EQ("::/0", prefixStr(0));
|
||||
|
||||
EXPECT_EQ("8000::/1", prefixStr(1));
|
||||
EXPECT_EQ("c000::/2", prefixStr(2));
|
||||
EXPECT_EQ("e000::/3", prefixStr(3));
|
||||
EXPECT_EQ("f000::/4", prefixStr(4));
|
||||
EXPECT_EQ("f800::/5", prefixStr(5));
|
||||
EXPECT_EQ("fc00::/6", prefixStr(6));
|
||||
EXPECT_EQ("fe00::/7", prefixStr(7));
|
||||
EXPECT_EQ("ff00::/8", prefixStr(8));
|
||||
|
||||
EXPECT_EQ("ff80::/9", prefixStr(9));
|
||||
EXPECT_EQ("ffc0::/10", prefixStr(10));
|
||||
EXPECT_EQ("ffe0::/11", prefixStr(11));
|
||||
EXPECT_EQ("fff0::/12", prefixStr(12));
|
||||
EXPECT_EQ("fff8::/13", prefixStr(13));
|
||||
EXPECT_EQ("fffc::/14", prefixStr(14));
|
||||
EXPECT_EQ("fffe::/15", prefixStr(15));
|
||||
EXPECT_EQ("ffff::/16", prefixStr(16));
|
||||
|
||||
EXPECT_EQ("ffff:8000::/17", prefixStr(17));
|
||||
EXPECT_EQ("ffff:c000::/18", prefixStr(18));
|
||||
EXPECT_EQ("ffff:e000::/19", prefixStr(19));
|
||||
EXPECT_EQ("ffff:f000::/20", prefixStr(20));
|
||||
EXPECT_EQ("ffff:f800::/21", prefixStr(21));
|
||||
EXPECT_EQ("ffff:fc00::/22", prefixStr(22));
|
||||
EXPECT_EQ("ffff:fe00::/23", prefixStr(23));
|
||||
EXPECT_EQ("ffff:ff00::/24", prefixStr(24));
|
||||
|
||||
EXPECT_EQ("ffff:ff80::/25", prefixStr(25));
|
||||
EXPECT_EQ("ffff:ffc0::/26", prefixStr(26));
|
||||
EXPECT_EQ("ffff:ffe0::/27", prefixStr(27));
|
||||
EXPECT_EQ("ffff:fff0::/28", prefixStr(28));
|
||||
EXPECT_EQ("ffff:fff8::/29", prefixStr(29));
|
||||
EXPECT_EQ("ffff:fffc::/30", prefixStr(30));
|
||||
EXPECT_EQ("ffff:fffe::/31", prefixStr(31));
|
||||
EXPECT_EQ("ffff:ffff::/32", prefixStr(32));
|
||||
|
||||
EXPECT_EQ("ffff:ffff:8000::/33", prefixStr(33));
|
||||
EXPECT_EQ("ffff:ffff:c000::/34", prefixStr(34));
|
||||
EXPECT_EQ("ffff:ffff:e000::/35", prefixStr(35));
|
||||
EXPECT_EQ("ffff:ffff:f000::/36", prefixStr(36));
|
||||
EXPECT_EQ("ffff:ffff:f800::/37", prefixStr(37));
|
||||
EXPECT_EQ("ffff:ffff:fc00::/38", prefixStr(38));
|
||||
EXPECT_EQ("ffff:ffff:fe00::/39", prefixStr(39));
|
||||
EXPECT_EQ("ffff:ffff:ff00::/40", prefixStr(40));
|
||||
|
||||
EXPECT_EQ("ffff:ffff:ff80::/41", prefixStr(41));
|
||||
EXPECT_EQ("ffff:ffff:ffc0::/42", prefixStr(42));
|
||||
EXPECT_EQ("ffff:ffff:ffe0::/43", prefixStr(43));
|
||||
EXPECT_EQ("ffff:ffff:fff0::/44", prefixStr(44));
|
||||
EXPECT_EQ("ffff:ffff:fff8::/45", prefixStr(45));
|
||||
EXPECT_EQ("ffff:ffff:fffc::/46", prefixStr(46));
|
||||
EXPECT_EQ("ffff:ffff:fffe::/47", prefixStr(47));
|
||||
EXPECT_EQ("ffff:ffff:ffff::/48", prefixStr(48));
|
||||
|
||||
EXPECT_EQ("ffff:ffff:ffff:8000::/49", prefixStr(49));
|
||||
EXPECT_EQ("ffff:ffff:ffff:c000::/50", prefixStr(50));
|
||||
EXPECT_EQ("ffff:ffff:ffff:e000::/51", prefixStr(51));
|
||||
EXPECT_EQ("ffff:ffff:ffff:f000::/52", prefixStr(52));
|
||||
EXPECT_EQ("ffff:ffff:ffff:f800::/53", prefixStr(53));
|
||||
EXPECT_EQ("ffff:ffff:ffff:fc00::/54", prefixStr(54));
|
||||
EXPECT_EQ("ffff:ffff:ffff:fe00::/55", prefixStr(55));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ff00::/56", prefixStr(56));
|
||||
|
||||
EXPECT_EQ("ffff:ffff:ffff:ff80::/57", prefixStr(57));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffc0::/58", prefixStr(58));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffe0::/59", prefixStr(59));
|
||||
EXPECT_EQ("ffff:ffff:ffff:fff0::/60", prefixStr(60));
|
||||
EXPECT_EQ("ffff:ffff:ffff:fff8::/61", prefixStr(61));
|
||||
EXPECT_EQ("ffff:ffff:ffff:fffc::/62", prefixStr(62));
|
||||
EXPECT_EQ("ffff:ffff:ffff:fffe::/63", prefixStr(63));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff::/64", prefixStr(64));
|
||||
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:8000::/65", prefixStr(65));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:c000::/66", prefixStr(66));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:e000::/67", prefixStr(67));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:f000::/68", prefixStr(68));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:f800::/69", prefixStr(69));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:fc00::/70", prefixStr(70));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:fe00::/71", prefixStr(71));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ff00::/72", prefixStr(72));
|
||||
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ff80::/73", prefixStr(73));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffc0::/74", prefixStr(74));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffe0::/75", prefixStr(75));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:fff0::/76", prefixStr(76));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:fff8::/77", prefixStr(77));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:fffc::/78", prefixStr(78));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:fffe::/79", prefixStr(79));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff::/80", prefixStr(80));
|
||||
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:8000::/81", prefixStr(81));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:c000::/82", prefixStr(82));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:e000::/83", prefixStr(83));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:f000::/84", prefixStr(84));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:f800::/85", prefixStr(85));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fc00::/86", prefixStr(86));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fe00::/87", prefixStr(87));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ff00::/88", prefixStr(88));
|
||||
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ff80::/89", prefixStr(89));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffc0::/90", prefixStr(90));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffe0::/91", prefixStr(91));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fff0::/92", prefixStr(92));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fff8::/93", prefixStr(93));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fffc::/94", prefixStr(94));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fffe::/95", prefixStr(95));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff::/96", prefixStr(96));
|
||||
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:8000:0/97", prefixStr(97));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:c000:0/98", prefixStr(98));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:e000:0/99", prefixStr(99));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:f000:0/100", prefixStr(100));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:f800:0/101", prefixStr(101));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fc00:0/102", prefixStr(102));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fe00:0/103", prefixStr(103));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ff00:0/104", prefixStr(104));
|
||||
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ff80:0/105", prefixStr(105));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffc0:0/106", prefixStr(106));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffe0:0/107", prefixStr(107));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fff0:0/108", prefixStr(108));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fff8:0/109", prefixStr(109));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fffc:0/110", prefixStr(110));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fffe:0/111", prefixStr(111));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:0/112", prefixStr(112));
|
||||
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:8000/113", prefixStr(113));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:c000/114", prefixStr(114));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:e000/115", prefixStr(115));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:f000/116", prefixStr(116));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:f800/117", prefixStr(117));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fc00/118", prefixStr(118));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fe00/119", prefixStr(119));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00/120", prefixStr(120));
|
||||
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff80/121", prefixStr(121));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffc0/122", prefixStr(122));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffe0/123", prefixStr(123));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0/124", prefixStr(124));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff8/125", prefixStr(125));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc/126", prefixStr(126));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe/127", prefixStr(127));
|
||||
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128", prefixStr(128));
|
||||
}
|
||||
|
||||
TEST(IPPrefixTest, TruncationOther) {
|
||||
const struct {
|
||||
const char* ip;
|
||||
const int cidrLen;
|
||||
const char* ipTruncated;
|
||||
} testExpectations[] = {
|
||||
{"192.0.2.0", 24, "192.0.2.0"},
|
||||
{"192.0.2.0", 23, "192.0.2.0"},
|
||||
{"192.0.2.0", 22, "192.0.0.0"},
|
||||
{"192.0.2.0", 1, "128.0.0.0"},
|
||||
{"2001:db8:cafe:d00d::", 56, "2001:db8:cafe:d000::"},
|
||||
{"2001:db8:cafe:d00d::", 48, "2001:db8:cafe::"},
|
||||
{"2001:db8:cafe:d00d::", 47, "2001:db8:cafe::"},
|
||||
{"2001:db8:cafe:d00d::", 46, "2001:db8:cafc::"},
|
||||
};
|
||||
|
||||
for (const auto& expectation : testExpectations) {
|
||||
IPAddress ip;
|
||||
EXPECT_TRUE(IPAddress::forString(expectation.ip, &ip))
|
||||
<< "Failed to parse IP address " << expectation.ip;
|
||||
|
||||
IPAddress ipTruncated;
|
||||
EXPECT_TRUE(IPAddress::forString(expectation.ipTruncated, &ipTruncated))
|
||||
<< "Failed to parse IP address " << expectation.ipTruncated;
|
||||
|
||||
IPPrefix prefix(ip, expectation.cidrLen);
|
||||
|
||||
EXPECT_EQ(expectation.cidrLen, prefix.length())
|
||||
<< "Unexpected cidrLen " << expectation.cidrLen;
|
||||
EXPECT_EQ(ipTruncated, prefix.ip())
|
||||
<< "Unexpected IP truncation: " << prefix.ip() << ", expected: " << ipTruncated;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IPPrefixTest, GamutOfOperators) {
|
||||
const std::vector<OperatorExpectation<IPPrefix>> kExpectations{
|
||||
{EQ, IPPrefix(), IPPrefix()},
|
||||
{EQ, IPPrefix(IPAddress(IPV4_ANY), 0), IPPrefix(IPAddress(IPV4_ANY), 0)},
|
||||
{EQ, IPPrefix(IPAddress(IPV4_ANY), IPV4_ADDR_BITS), IPPrefix(IPAddress(IPV4_ANY))},
|
||||
{EQ, IPPrefix(IPAddress(IPV6_ANY), 0), IPPrefix(IPAddress(IPV6_ANY), 0)},
|
||||
{EQ, IPPrefix(IPAddress(IPV6_ANY), IPV6_ADDR_BITS), IPPrefix(IPAddress(IPV6_ANY))},
|
||||
// Needlessly fully-specified IPv6 link-local address.
|
||||
{EQ, IPPrefix(IPAddress(FE80_1)), IPPrefix(IPAddress(FE80_1, 0), IPV6_ADDR_BITS)},
|
||||
// Different IPv6 link-local addresses within the same /64, no scoped_id: same /64.
|
||||
{EQ, IPPrefix(IPAddress(FE80_1), 64), IPPrefix(IPAddress(FE80_2), 64)},
|
||||
// Different IPv6 link-local address within the same /64, same scoped_id: same /64.
|
||||
{EQ, IPPrefix(IPAddress(FE80_1, 17), 64), IPPrefix(IPAddress(FE80_2, 17), 64)},
|
||||
// Unspecified < IPv4.
|
||||
{LT, IPPrefix(), IPPrefix(IPAddress(IPV4_ANY), 0)},
|
||||
// Same IPv4 base address sorts by prefix length.
|
||||
{LT, IPPrefix(IPAddress(IPV4_ANY), 0), IPPrefix(IPAddress(IPV4_ANY), 1)},
|
||||
{LT, IPPrefix(IPAddress(IPV4_ANY), 1), IPPrefix(IPAddress(IPV4_ANY), IPV4_ADDR_BITS)},
|
||||
// Truncation means each base IPv4 address is different.
|
||||
{LT, IPPrefix(IPAddress(IPV4_ONES), 0), IPPrefix(IPAddress(IPV4_ONES), 1)},
|
||||
{LT, IPPrefix(IPAddress(IPV4_ONES), 1), IPPrefix(IPAddress(IPV4_ONES), IPV4_ADDR_BITS)},
|
||||
// Sort by base IPv4 addresses first.
|
||||
{LT, IPPrefix(IPAddress(IPV4_ANY), 0), IPPrefix(IPAddress::forString("0.0.0.1"))},
|
||||
{LT, IPPrefix(IPAddress(IPV4_ANY), 1), IPPrefix(IPAddress::forString("0.0.0.1"))},
|
||||
{LT, IPPrefix(IPAddress(IPV4_ANY), 24), IPPrefix(IPAddress::forString("0.0.0.1"))},
|
||||
// IPv4 < IPv6.
|
||||
{LT, IPPrefix(IPAddress(IPV4_ANY), 0), IPPrefix(IPAddress(IPV6_ANY), 0)},
|
||||
{LT, IPPrefix(IPAddress(IPV4_ONES)), IPPrefix(IPAddress(IPV6_ANY))},
|
||||
// Unspecified < IPv6.
|
||||
{LT, IPPrefix(), IPPrefix(IPAddress(IPV6_ANY), 0)},
|
||||
// Same IPv6 base address sorts by prefix length.
|
||||
{LT, IPPrefix(IPAddress(IPV6_ANY), 0), IPPrefix(IPAddress(IPV6_ANY), 1)},
|
||||
{LT, IPPrefix(IPAddress(IPV6_ANY), 1), IPPrefix(IPAddress(IPV6_ANY), IPV6_ADDR_BITS)},
|
||||
// Truncation means each base IPv6 address is different.
|
||||
{LT, IPPrefix(IPAddress(IPV6_ONES), 0), IPPrefix(IPAddress(IPV6_ONES), 1)},
|
||||
{LT, IPPrefix(IPAddress(IPV6_ONES), 1), IPPrefix(IPAddress(IPV6_ONES), IPV6_ADDR_BITS)},
|
||||
// Different IPv6 link-local address in same /64, different scoped_id: different /64.
|
||||
{LT, IPPrefix(IPAddress(FE80_1, 17), 64), IPPrefix(IPAddress(FE80_2, 22), 64)},
|
||||
{LT, IPPrefix(IPAddress(FE80_1, 17), 64), IPPrefix(IPAddress(FE80_1, 18), 64)},
|
||||
{LT, IPPrefix(IPAddress(FE80_1, 18), 64), IPPrefix(IPAddress(FE80_1, 19), 64)},
|
||||
};
|
||||
|
||||
size_t tests_run = 0;
|
||||
for (const auto& expectation : kExpectations) {
|
||||
SCOPED_TRACE(expectation.toString());
|
||||
EXPECT_NO_FATAL_FAILURE(testGamutOfOperators(expectation));
|
||||
tests_run++;
|
||||
}
|
||||
EXPECT_EQ(kExpectations.size(), tests_run);
|
||||
}
|
||||
|
||||
TEST(IPSockAddrTest, GamutOfOperators) {
|
||||
const std::vector<OperatorExpectation<IPSockAddr>> kExpectations{
|
||||
{EQ, IPSockAddr(), IPSockAddr()},
|
||||
{EQ, IPSockAddr(IPAddress(IPV4_ANY)), IPSockAddr(IPAddress(IPV4_ANY), 0)},
|
||||
{EQ, IPSockAddr(IPAddress(IPV6_ANY)), IPSockAddr(IPAddress(IPV6_ANY), 0)},
|
||||
{EQ, IPSockAddr(IPAddress(FE80_1), 80), IPSockAddr(IPAddress(FE80_1), 80)},
|
||||
{EQ, IPSockAddr(IPAddress(FE80_1, 17)), IPSockAddr(IPAddress(FE80_1, 17), 0)},
|
||||
{LT, IPSockAddr(IPAddress(IPV4_ANY), 0), IPSockAddr(IPAddress(IPV4_ANY), 1)},
|
||||
{LT, IPSockAddr(IPAddress(IPV4_ANY), 53), IPSockAddr(IPAddress(IPV4_ANY), 123)},
|
||||
{LT, IPSockAddr(IPAddress(IPV4_ONES), 123), IPSockAddr(IPAddress(IPV6_ANY), 53)},
|
||||
{LT, IPSockAddr(IPAddress(IPV6_ANY), 0), IPSockAddr(IPAddress(IPV6_ANY), 1)},
|
||||
{LT, IPSockAddr(IPAddress(IPV6_ANY), 53), IPSockAddr(IPAddress(IPV6_ANY), 123)},
|
||||
{LT, IPSockAddr(IPAddress(FE80_1), 80), IPSockAddr(IPAddress(FE80_1, 17), 80)},
|
||||
{LT, IPSockAddr(IPAddress(FE80_1, 17), 80), IPSockAddr(IPAddress(FE80_1, 22), 80)},
|
||||
};
|
||||
|
||||
size_t tests_run = 0;
|
||||
for (const auto& expectation : kExpectations) {
|
||||
SCOPED_TRACE(expectation.toString());
|
||||
EXPECT_NO_FATAL_FAILURE(testGamutOfOperators(expectation));
|
||||
tests_run++;
|
||||
}
|
||||
EXPECT_EQ(kExpectations.size(), tests_run);
|
||||
}
|
||||
|
||||
TEST(IPSockAddrTest, toString) {
|
||||
EXPECT_EQ("<unspecified>:0", IPSockAddr().toString());
|
||||
EXPECT_EQ("0.0.0.0:0", IPSockAddr(IPAddress(IPV4_ANY)).toString());
|
||||
EXPECT_EQ("255.255.255.255:67", IPSockAddr(IPAddress(IPV4_ONES), 67).toString());
|
||||
EXPECT_EQ("[::]:0", IPSockAddr(IPAddress(IPV6_ANY)).toString());
|
||||
EXPECT_EQ("[::1]:53", IPSockAddr(IPAddress(IPV6_LOOPBACK), 53).toString());
|
||||
EXPECT_EQ("[fe80::1]:0", IPSockAddr(IPAddress(FE80_1)).toString());
|
||||
EXPECT_EQ("[fe80::2%17]:123", IPSockAddr(IPAddress(FE80_2, 17), 123).toString());
|
||||
}
|
||||
|
||||
TEST(CompatIPDataTest, ConversionsClearUnneededValues) {
|
||||
const uint32_t idx = 17;
|
||||
const IPSockAddr linkLocalNtpSockaddr(IPAddress(FE80_2, idx), 123);
|
||||
EXPECT_EQ(IPAddress(FE80_2, idx), linkLocalNtpSockaddr.ip());
|
||||
// IPSockAddr(IPSockaddr.ip()) see the port cleared.
|
||||
EXPECT_EQ(0, IPSockAddr(linkLocalNtpSockaddr.ip()).port());
|
||||
const IPPrefix linkLocalPrefix(linkLocalNtpSockaddr.ip(), 64);
|
||||
EXPECT_EQ(IPAddress(FE80, idx), linkLocalPrefix.ip());
|
||||
// IPPrefix(IPPrefix.ip()) see the CIDR length cleared.
|
||||
EXPECT_EQ(IPV6_ADDR_BITS, IPPrefix(linkLocalPrefix.ip()).length());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
216
staticlibs/netd/libnetdutils/Log.cpp
Normal file
216
staticlibs/netd/libnetdutils/Log.cpp
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 "netdutils/Log.h"
|
||||
#include "netdutils/Slice.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
|
||||
#include <android-base/strings.h>
|
||||
#include <log/log.h>
|
||||
|
||||
using ::android::base::Join;
|
||||
using ::android::base::StringPrintf;
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string makeTimestampedEntry(const std::string& entry) {
|
||||
using ::std::chrono::duration_cast;
|
||||
using ::std::chrono::milliseconds;
|
||||
using ::std::chrono::system_clock;
|
||||
|
||||
std::stringstream tsEntry;
|
||||
const auto now = system_clock::now();
|
||||
const auto time_sec = system_clock::to_time_t(now);
|
||||
tsEntry << std::put_time(std::localtime(&time_sec), "%m-%d %H:%M:%S.") << std::setw(3)
|
||||
<< std::setfill('0')
|
||||
<< duration_cast<milliseconds>(now - system_clock::from_time_t(time_sec)).count() << " "
|
||||
<< entry;
|
||||
|
||||
return tsEntry.str();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string LogEntry::toString() const {
|
||||
std::vector<std::string> text;
|
||||
|
||||
if (!mMsg.empty()) text.push_back(mMsg);
|
||||
if (!mFunc.empty()) {
|
||||
text.push_back(StringPrintf("%s(%s)", mFunc.c_str(), Join(mArgs, ", ").c_str()));
|
||||
}
|
||||
if (!mReturns.empty()) {
|
||||
text.push_back("->");
|
||||
text.push_back(StringPrintf("(%s)", Join(mReturns, ", ").c_str()));
|
||||
}
|
||||
if (!mUid.empty()) text.push_back(mUid);
|
||||
if (!mDuration.empty()) text.push_back(StringPrintf("(%s)", mDuration.c_str()));
|
||||
|
||||
return Join(text, " ");
|
||||
}
|
||||
|
||||
LogEntry& LogEntry::message(const std::string& message) {
|
||||
mMsg = message;
|
||||
return *this;
|
||||
}
|
||||
|
||||
LogEntry& LogEntry::function(const std::string& function_name) {
|
||||
mFunc = function_name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
LogEntry& LogEntry::prettyFunction(const std::string& pretty_function) {
|
||||
// __PRETTY_FUNCTION__ generally seems to be of the form:
|
||||
//
|
||||
// qualifed::returnType qualified::function(args...)
|
||||
//
|
||||
// where the qualified forms include "(anonymous namespace)" in the
|
||||
// "::"-delimited list and keywords like "virtual" (where applicable).
|
||||
//
|
||||
// Here we try to convert strings like:
|
||||
//
|
||||
// virtual binder::Status android::net::NetdNativeService::isAlive(bool *)
|
||||
// netdutils::LogEntry android::netd::(anonymous namespace)::AAA::BBB::function()
|
||||
//
|
||||
// into just "NetdNativeService::isAlive" or "BBB::function". Note that
|
||||
// without imposing convention, how to easily identify any namespace/class
|
||||
// name boundary is not obvious.
|
||||
const size_t endFuncName = pretty_function.rfind('(');
|
||||
const size_t precedingSpace = pretty_function.rfind(' ', endFuncName);
|
||||
size_t substrStart = (precedingSpace != std::string::npos) ? precedingSpace + 1 : 0;
|
||||
|
||||
const size_t beginFuncName = pretty_function.rfind("::", endFuncName);
|
||||
if (beginFuncName != std::string::npos && substrStart < beginFuncName) {
|
||||
const size_t previousNameBoundary = pretty_function.rfind("::", beginFuncName - 1);
|
||||
if (previousNameBoundary < beginFuncName && substrStart < previousNameBoundary) {
|
||||
substrStart = previousNameBoundary + 2;
|
||||
} else {
|
||||
substrStart = beginFuncName + 2;
|
||||
}
|
||||
}
|
||||
|
||||
mFunc = pretty_function.substr(substrStart, endFuncName - substrStart);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LogEntry& LogEntry::arg(const std::string& val) {
|
||||
mArgs.push_back(val.empty() ? "\"\"" : val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <>
|
||||
LogEntry& LogEntry::arg<>(bool val) {
|
||||
mArgs.push_back(val ? "true" : "false");
|
||||
return *this;
|
||||
}
|
||||
|
||||
LogEntry& LogEntry::arg(const std::vector<int32_t>& val) {
|
||||
mArgs.push_back(StringPrintf("[%s]", Join(val, ", ").c_str()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
LogEntry& LogEntry::arg(const std::vector<uint8_t>& val) {
|
||||
mArgs.push_back('{' + toHex(makeSlice(val)) + '}');
|
||||
return *this;
|
||||
}
|
||||
|
||||
LogEntry& LogEntry::arg(const std::vector<std::string>& val) {
|
||||
mArgs.push_back(StringPrintf("[%s]", Join(val, ", ").c_str()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
LogEntry& LogEntry::returns(const std::string& rval) {
|
||||
mReturns.push_back(rval);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LogEntry& LogEntry::returns(bool rval) {
|
||||
mReturns.push_back(rval ? "true" : "false");
|
||||
return *this;
|
||||
}
|
||||
|
||||
LogEntry& LogEntry::returns(const Status& status) {
|
||||
mReturns.push_back(status.msg());
|
||||
return *this;
|
||||
}
|
||||
|
||||
LogEntry& LogEntry::withUid(uid_t uid) {
|
||||
mUid = StringPrintf("(uid=%d)", uid);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LogEntry& LogEntry::withAutomaticDuration() {
|
||||
using ms = std::chrono::duration<float, std::ratio<1, 1000>>;
|
||||
|
||||
const std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
|
||||
std::stringstream duration;
|
||||
duration << std::setprecision(1) << std::chrono::duration_cast<ms>(end - mStart).count()
|
||||
<< "ms";
|
||||
mDuration = duration.str();
|
||||
return *this;
|
||||
}
|
||||
|
||||
LogEntry& LogEntry::withDuration(const std::string& duration) {
|
||||
mDuration = duration;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Log::~Log() {
|
||||
// TODO: dump the last N entries to the android log for possible posterity.
|
||||
info(LogEntry().function(__FUNCTION__));
|
||||
}
|
||||
|
||||
void Log::forEachEntry(const std::function<void(const std::string&)>& perEntryFn) const {
|
||||
// We make a (potentially expensive) copy of the log buffer (including
|
||||
// all strings), in case the |perEntryFn| takes its sweet time.
|
||||
std::deque<std::string> entries;
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> guard(mLock);
|
||||
entries.assign(mEntries.cbegin(), mEntries.cend());
|
||||
}
|
||||
|
||||
for (const std::string& entry : entries) perEntryFn(entry);
|
||||
}
|
||||
|
||||
void Log::record(Log::Level lvl, const std::string& entry) {
|
||||
switch (lvl) {
|
||||
case Level::LOG:
|
||||
break;
|
||||
case Level::INFO:
|
||||
ALOG(LOG_INFO, mTag.c_str(), "%s", entry.c_str());
|
||||
break;
|
||||
case Level::WARN:
|
||||
ALOG(LOG_WARN, mTag.c_str(), "%s", entry.c_str());
|
||||
break;
|
||||
case Level::ERROR:
|
||||
ALOG(LOG_ERROR, mTag.c_str(), "%s", entry.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
std::lock_guard guard(mLock);
|
||||
mEntries.push_back(makeTimestampedEntry(entry));
|
||||
while (mEntries.size() > mMaxEntries) mEntries.pop_front();
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
143
staticlibs/netd/libnetdutils/LogTest.cpp
Normal file
143
staticlibs/netd/libnetdutils/LogTest.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 <gtest/gtest.h>
|
||||
|
||||
#include "netdutils/Log.h"
|
||||
|
||||
android::netdutils::LogEntry globalFunctionName() {
|
||||
return android::netdutils::LogEntry().function(__FUNCTION__);
|
||||
}
|
||||
|
||||
android::netdutils::LogEntry globalPrettyFunctionName() {
|
||||
return android::netdutils::LogEntry().prettyFunction(__PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
namespace {
|
||||
|
||||
LogEntry functionName() {
|
||||
return LogEntry().function(__FUNCTION__);
|
||||
}
|
||||
|
||||
LogEntry prettyFunctionName() {
|
||||
return LogEntry().prettyFunction(__PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class AAA {
|
||||
public:
|
||||
AAA() = default;
|
||||
|
||||
LogEntry functionName() {
|
||||
return LogEntry().function(__FUNCTION__);
|
||||
}
|
||||
|
||||
LogEntry prettyFunctionName() {
|
||||
return LogEntry().prettyFunction(__PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
class BBB {
|
||||
public:
|
||||
BBB() = default;
|
||||
|
||||
LogEntry functionName() {
|
||||
return LogEntry().function(__FUNCTION__);
|
||||
}
|
||||
|
||||
LogEntry prettyFunctionName() {
|
||||
return LogEntry().prettyFunction(__PRETTY_FUNCTION__);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
TEST(LogEntryTest, Empty) {
|
||||
LogEntry empty;
|
||||
EXPECT_EQ("", empty.toString());
|
||||
}
|
||||
|
||||
TEST(LogEntryTest, GlobalFunction) {
|
||||
EXPECT_EQ("globalFunctionName()", ::globalFunctionName().toString());
|
||||
}
|
||||
|
||||
TEST(LogEntryTest, GlobalPrettyFunction) {
|
||||
EXPECT_EQ("globalPrettyFunctionName()", ::globalPrettyFunctionName().toString());
|
||||
}
|
||||
|
||||
TEST(LogEntryTest, UnnamedNamespaceFunction) {
|
||||
const LogEntry entry = functionName();
|
||||
EXPECT_EQ("functionName()", entry.toString());
|
||||
}
|
||||
|
||||
TEST(LogEntryTest, UnnamedNamespacePrettyFunction) {
|
||||
const LogEntry entry = prettyFunctionName();
|
||||
EXPECT_EQ("prettyFunctionName()", entry.toString());
|
||||
}
|
||||
|
||||
TEST(LogEntryTest, ClassFunction) {
|
||||
const LogEntry entry = AAA().functionName();
|
||||
EXPECT_EQ("functionName()", entry.toString());
|
||||
}
|
||||
|
||||
TEST(LogEntryTest, ClassPrettyFunction) {
|
||||
const LogEntry entry = AAA().prettyFunctionName();
|
||||
EXPECT_EQ("AAA::prettyFunctionName()", entry.toString());
|
||||
}
|
||||
|
||||
TEST(LogEntryTest, InnerClassFunction) {
|
||||
const LogEntry entry = AAA::BBB().functionName();
|
||||
EXPECT_EQ("functionName()", entry.toString());
|
||||
}
|
||||
|
||||
TEST(LogEntryTest, InnerClassPrettyFunction) {
|
||||
const LogEntry entry = AAA::BBB().prettyFunctionName();
|
||||
EXPECT_EQ("BBB::prettyFunctionName()", entry.toString());
|
||||
}
|
||||
|
||||
TEST(LogEntryTest, PrintChainedArguments) {
|
||||
const LogEntry entry = LogEntry()
|
||||
.function("testFunc")
|
||||
.arg("hello")
|
||||
.arg(42)
|
||||
.arg(true);
|
||||
EXPECT_EQ("testFunc(hello, 42, true)", entry.toString());
|
||||
}
|
||||
|
||||
TEST(LogEntryTest, PrintIntegralTypes) {
|
||||
const LogEntry entry = LogEntry()
|
||||
.function("testFunc")
|
||||
.arg('A')
|
||||
.arg(100U)
|
||||
.arg(-1000LL);
|
||||
EXPECT_EQ("testFunc(65, 100, -1000)", entry.toString());
|
||||
}
|
||||
|
||||
TEST(LogEntryTest, PrintHex) {
|
||||
const std::vector<uint8_t> buf{0xDE, 0xAD, 0xBE, 0xEF};
|
||||
const LogEntry entry = LogEntry().function("testFunc").arg(buf);
|
||||
EXPECT_EQ("testFunc({deadbeef})", entry.toString());
|
||||
}
|
||||
|
||||
TEST(LogEntryTest, PrintArgumentPack) {
|
||||
const LogEntry entry = LogEntry().function("testFunc").args("hello", 42, false);
|
||||
EXPECT_EQ("testFunc(hello, 42, false)", entry.toString());
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
146
staticlibs/netd/libnetdutils/MemBlockTest.cpp
Normal file
146
staticlibs/netd/libnetdutils/MemBlockTest.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 <algorithm>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "netdutils/MemBlock.h"
|
||||
#include "netdutils/Slice.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr unsigned DNS_PACKET_SIZE = 512;
|
||||
constexpr int ARBITRARY_VALUE = 0x55;
|
||||
|
||||
MemBlock makeArbitraryMemBlock(size_t len) {
|
||||
MemBlock result(len);
|
||||
// Do some fictional work before returning.
|
||||
for (Slice slice = result.get(); !slice.empty(); slice = drop(slice, 1)) {
|
||||
slice.base()[0] = ARBITRARY_VALUE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void checkAllZeros(Slice slice) {
|
||||
for (; !slice.empty(); slice = drop(slice, 1)) {
|
||||
EXPECT_EQ(0U, slice.base()[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void checkArbitraryMemBlock(const MemBlock& block, size_t expectedSize) {
|
||||
Slice slice = block.get();
|
||||
EXPECT_EQ(expectedSize, slice.size());
|
||||
EXPECT_NE(nullptr, slice.base());
|
||||
for (; !slice.empty(); slice = drop(slice, 1)) {
|
||||
EXPECT_EQ(ARBITRARY_VALUE, slice.base()[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void checkHelloMello(Slice dest, Slice src) {
|
||||
EXPECT_EQ('h', dest.base()[0]);
|
||||
EXPECT_EQ('e', dest.base()[1]);
|
||||
EXPECT_EQ('l', dest.base()[2]);
|
||||
EXPECT_EQ('l', dest.base()[3]);
|
||||
EXPECT_EQ('o', dest.base()[4]);
|
||||
|
||||
src.base()[0] = 'm';
|
||||
EXPECT_EQ('h', dest.base()[0]);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(MemBlockTest, Empty) {
|
||||
MemBlock empty;
|
||||
EXPECT_TRUE(empty.get().empty());
|
||||
EXPECT_EQ(nullptr, empty.get().base());
|
||||
}
|
||||
|
||||
TEST(MemBlockTest, ExplicitZero) {
|
||||
MemBlock zero(0);
|
||||
EXPECT_TRUE(zero.get().empty());
|
||||
EXPECT_EQ(nullptr, zero.get().base());
|
||||
}
|
||||
|
||||
TEST(MemBlockTest, BasicAllocation) {
|
||||
MemBlock dnsPacket(DNS_PACKET_SIZE);
|
||||
Slice slice = dnsPacket.get();
|
||||
EXPECT_EQ(DNS_PACKET_SIZE, slice.size());
|
||||
// Verify the space is '\0'-initialized.
|
||||
ASSERT_NO_FATAL_FAILURE(checkAllZeros(slice));
|
||||
EXPECT_NE(nullptr, slice.base());
|
||||
}
|
||||
|
||||
TEST(MemBlockTest, MoveConstruction) {
|
||||
MemBlock block(makeArbitraryMemBlock(DNS_PACKET_SIZE));
|
||||
ASSERT_NO_FATAL_FAILURE(checkArbitraryMemBlock(block, DNS_PACKET_SIZE));
|
||||
}
|
||||
|
||||
TEST(MemBlockTest, MoveAssignmentOrConstruction) {
|
||||
MemBlock block = makeArbitraryMemBlock(DNS_PACKET_SIZE);
|
||||
ASSERT_NO_FATAL_FAILURE(checkArbitraryMemBlock(block, DNS_PACKET_SIZE));
|
||||
}
|
||||
|
||||
TEST(MemBlockTest, StdMoveAssignment) {
|
||||
constexpr unsigned SIZE = 10;
|
||||
|
||||
MemBlock block;
|
||||
EXPECT_TRUE(block.get().empty());
|
||||
EXPECT_EQ(nullptr, block.get().base());
|
||||
|
||||
{
|
||||
MemBlock block2 = makeArbitraryMemBlock(SIZE);
|
||||
EXPECT_EQ(SIZE, block2.get().size());
|
||||
// More fictional work.
|
||||
for (unsigned i = 0; i < SIZE; i++) {
|
||||
block2.get().base()[i] = i;
|
||||
}
|
||||
block = std::move(block2);
|
||||
}
|
||||
|
||||
EXPECT_EQ(SIZE, block.get().size());
|
||||
for (unsigned i = 0; i < SIZE; i++) {
|
||||
EXPECT_EQ(i, block.get().base()[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MemBlockTest, ConstructionFromSlice) {
|
||||
uint8_t data[] = {'h', 'e', 'l', 'l', 'o'};
|
||||
Slice dataSlice(Slice(data, sizeof(data) / sizeof(data[0])));
|
||||
|
||||
MemBlock dataCopy(dataSlice);
|
||||
ASSERT_NO_FATAL_FAILURE(checkHelloMello(dataCopy.get(), dataSlice));
|
||||
}
|
||||
|
||||
TEST(MemBlockTest, ImplicitCastToSlice) {
|
||||
uint8_t data[] = {'h', 'e', 'l', 'l', 'o'};
|
||||
Slice dataSlice(Slice(data, sizeof(data) / sizeof(data[0])));
|
||||
|
||||
MemBlock dataCopy(dataSlice.size());
|
||||
// NOTE: no explicit MemBlock::get().
|
||||
// Verify the space is '\0'-initialized.
|
||||
ASSERT_NO_FATAL_FAILURE(checkAllZeros(dataCopy));
|
||||
copy(dataCopy, dataSlice);
|
||||
ASSERT_NO_FATAL_FAILURE(checkHelloMello(dataCopy, dataSlice));
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
30
staticlibs/netd/libnetdutils/Netfilter.cpp
Normal file
30
staticlibs/netd/libnetdutils/Netfilter.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 <arpa/inet.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <ios>
|
||||
|
||||
#include "netdutils/Netfilter.h"
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const nfgenmsg& msg) {
|
||||
return os << std::hex << "nfgenmsg["
|
||||
<< "family: 0x" << static_cast<int>(msg.nfgen_family) << ", version: 0x"
|
||||
<< static_cast<int>(msg.version) << ", res_id: 0x" << ntohs(msg.res_id) << "]"
|
||||
<< std::dec;
|
||||
}
|
||||
78
staticlibs/netd/libnetdutils/Netlink.cpp
Normal file
78
staticlibs/netd/libnetdutils/Netlink.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 <ios>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#include "netdutils/Math.h"
|
||||
#include "netdutils/Netlink.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
void forEachNetlinkMessage(const Slice buf,
|
||||
const std::function<void(const nlmsghdr&, const Slice)>& onMsg) {
|
||||
Slice tail = buf;
|
||||
while (tail.size() >= sizeof(nlmsghdr)) {
|
||||
nlmsghdr hdr = {};
|
||||
extract(tail, hdr);
|
||||
const auto len = std::max<size_t>(hdr.nlmsg_len, sizeof(hdr));
|
||||
onMsg(hdr, drop(take(tail, len), sizeof(hdr)));
|
||||
tail = drop(tail, align(len, 2));
|
||||
}
|
||||
}
|
||||
|
||||
void forEachNetlinkAttribute(const Slice buf,
|
||||
const std::function<void(const nlattr&, const Slice)>& onAttr) {
|
||||
Slice tail = buf;
|
||||
while (tail.size() >= sizeof(nlattr)) {
|
||||
nlattr hdr = {};
|
||||
extract(tail, hdr);
|
||||
const auto len = std::max<size_t>(hdr.nla_len, sizeof(hdr));
|
||||
onAttr(hdr, drop(take(tail, len), sizeof(hdr)));
|
||||
tail = drop(tail, align(len, 2));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
bool operator==(const sockaddr_nl& lhs, const sockaddr_nl& rhs) {
|
||||
return (lhs.nl_family == rhs.nl_family) && (lhs.nl_pid == rhs.nl_pid) &&
|
||||
(lhs.nl_groups == rhs.nl_groups);
|
||||
}
|
||||
|
||||
bool operator!=(const sockaddr_nl& lhs, const sockaddr_nl& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const nlmsghdr& hdr) {
|
||||
return os << std::hex << "nlmsghdr["
|
||||
<< "len: 0x" << hdr.nlmsg_len << ", type: 0x" << hdr.nlmsg_type << ", flags: 0x"
|
||||
<< hdr.nlmsg_flags << ", seq: 0x" << hdr.nlmsg_seq << ", pid: 0x" << hdr.nlmsg_pid
|
||||
<< "]" << std::dec;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const nlattr& attr) {
|
||||
return os << std::hex << "nlattr["
|
||||
<< "len: 0x" << attr.nla_len << ", type: 0x" << attr.nla_type << "]" << std::dec;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const sockaddr_nl& addr) {
|
||||
return os << std::hex << "sockaddr_nl["
|
||||
<< "family: " << addr.nl_family << ", pid: " << addr.nl_pid
|
||||
<< ", groups: " << addr.nl_groups << "]" << std::dec;
|
||||
}
|
||||
61
staticlibs/netd/libnetdutils/Slice.cpp
Normal file
61
staticlibs/netd/libnetdutils/Slice.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 <sstream>
|
||||
|
||||
#include "netdutils/Slice.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
namespace {
|
||||
|
||||
// Convert one byte to a two character hexadecimal string
|
||||
const std::string toHex(uint8_t byte) {
|
||||
const std::array<char, 16> kLookup = {
|
||||
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}};
|
||||
return {kLookup[byte >> 4], kLookup[byte & 0xf]};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string toString(const Slice s) {
|
||||
return std::string(reinterpret_cast<char*>(s.base()), s.size());
|
||||
}
|
||||
|
||||
std::string toHex(const Slice s, int wrap) {
|
||||
Slice tail = s;
|
||||
int count = 0;
|
||||
std::stringstream ss;
|
||||
while (!tail.empty()) {
|
||||
uint8_t byte = 0;
|
||||
extract(tail, byte);
|
||||
ss << toHex(byte);
|
||||
if ((++count % wrap) == 0) {
|
||||
ss << "\n";
|
||||
}
|
||||
tail = drop(tail, 1);
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Slice& slice) {
|
||||
return os << std::hex << "Slice[base: " << reinterpret_cast<void*>(slice.base())
|
||||
<< ", limit: " << reinterpret_cast<void*>(slice.limit()) << ", size: 0x"
|
||||
<< slice.size() << "]" << std::dec;
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
135
staticlibs/netd/libnetdutils/SliceTest.cpp
Normal file
135
staticlibs/netd/libnetdutils/SliceTest.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 <array>
|
||||
#include <cstdint>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "netdutils/Slice.h"
|
||||
#include "netdutils/Status.h"
|
||||
#include "netdutils/StatusOr.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
class SliceTest : public testing::Test {
|
||||
protected:
|
||||
std::array<char, 256> mRaw = {};
|
||||
};
|
||||
|
||||
TEST_F(SliceTest, smoke) {
|
||||
Slice s1 = makeSlice(mRaw);
|
||||
Slice s2 = makeSlice(mRaw);
|
||||
auto p = split(s1, 14);
|
||||
s2 = p.first; // avoid warn-unused error
|
||||
std::stringstream ss;
|
||||
ss << Slice();
|
||||
EXPECT_EQ("Slice[base: 0x0, limit: 0x0, size: 0x0]", ss.str());
|
||||
constexpr size_t kBytes = 14;
|
||||
EXPECT_EQ(s1.base(), take(s1, kBytes).base());
|
||||
EXPECT_EQ(kBytes, take(s1, kBytes).size());
|
||||
EXPECT_EQ(s1.base() + kBytes, drop(s1, kBytes).base());
|
||||
EXPECT_EQ(s1.size() - kBytes, drop(s1, kBytes).size());
|
||||
double a = 0;
|
||||
double b = 0;
|
||||
int c = 0;
|
||||
EXPECT_EQ(sizeof(a), extract(s1, a));
|
||||
EXPECT_EQ(sizeof(a) + sizeof(b), extract(s1, a, b));
|
||||
EXPECT_EQ(sizeof(a) + sizeof(b) + sizeof(c), extract(s1, a, b, c));
|
||||
}
|
||||
|
||||
TEST_F(SliceTest, constructor) {
|
||||
// Expect the following lines to compile
|
||||
Slice s1 = makeSlice(mRaw);
|
||||
Slice s2(s1);
|
||||
Slice s3 = s2;
|
||||
const Slice s4(s3);
|
||||
const Slice s5 = s4;
|
||||
s3 = s5;
|
||||
Slice s6(mRaw.data(), mRaw.size());
|
||||
Slice s7(mRaw.data(), mRaw.data() + mRaw.size());
|
||||
struct {
|
||||
int a;
|
||||
double b;
|
||||
float c;
|
||||
} anon;
|
||||
makeSlice(anon);
|
||||
EXPECT_EQ(reinterpret_cast<uint8_t*>(mRaw.data()), s1.base());
|
||||
EXPECT_EQ(reinterpret_cast<uint8_t*>(mRaw.data()) + mRaw.size(), s1.limit());
|
||||
EXPECT_EQ(mRaw.size(), s1.size());
|
||||
EXPECT_FALSE(mRaw.empty());
|
||||
EXPECT_TRUE(Slice().empty());
|
||||
EXPECT_TRUE(Slice(nullptr, static_cast<size_t>(0)).empty());
|
||||
EXPECT_TRUE(Slice(nullptr, nullptr).empty());
|
||||
}
|
||||
|
||||
TEST_F(SliceTest, extract) {
|
||||
struct A {
|
||||
int a, b;
|
||||
bool operator==(const A& other) const { return a == other.a && b == other.b; }
|
||||
};
|
||||
struct B {
|
||||
char str[12];
|
||||
bool b;
|
||||
int i;
|
||||
bool operator==(const B& other) const {
|
||||
return b == other.b && i == other.i && 0 == strncmp(str, other.str, 12);
|
||||
}
|
||||
};
|
||||
|
||||
A origA1 = {1, 2};
|
||||
A origA2 = {3, 4};
|
||||
B origB = {"hello world", true, 1234};
|
||||
|
||||
// Populate buffer for extracting.
|
||||
Slice buffer = makeSlice(mRaw);
|
||||
copy(buffer, makeSlice(origA1));
|
||||
copy(drop(buffer, sizeof(origA1)), makeSlice(origB));
|
||||
copy(drop(buffer, sizeof(origA1) + sizeof(origB)), makeSlice(origA2));
|
||||
|
||||
{
|
||||
// Non-variadic extract
|
||||
A a1{};
|
||||
size_t len = extract(buffer, a1);
|
||||
EXPECT_EQ(sizeof(A), len);
|
||||
EXPECT_EQ(origA1, a1);
|
||||
}
|
||||
|
||||
{
|
||||
// Variadic extract, 2 destinations
|
||||
A a1{};
|
||||
B b{};
|
||||
size_t len = extract(buffer, a1, b);
|
||||
EXPECT_EQ(sizeof(A) + sizeof(B), len);
|
||||
EXPECT_EQ(origA1, a1);
|
||||
EXPECT_EQ(origB, b);
|
||||
}
|
||||
|
||||
{
|
||||
// Variadic extract, 3 destinations
|
||||
A a1{}, a2{};
|
||||
B b{};
|
||||
size_t len = extract(buffer, a1, b, a2);
|
||||
EXPECT_EQ(2 * sizeof(A) + sizeof(B), len);
|
||||
EXPECT_EQ(origA1, a1);
|
||||
EXPECT_EQ(origB, b);
|
||||
EXPECT_EQ(origA2, a2);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
35
staticlibs/netd/libnetdutils/Socket.cpp
Normal file
35
staticlibs/netd/libnetdutils/Socket.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 <arpa/inet.h>
|
||||
|
||||
#include "netdutils/Slice.h"
|
||||
#include "netdutils/Socket.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
StatusOr<std::string> toString(const in6_addr& addr) {
|
||||
std::array<char, INET6_ADDRSTRLEN> out = {};
|
||||
auto* rv = inet_ntop(AF_INET6, &addr, out.data(), out.size());
|
||||
if (rv == nullptr) {
|
||||
return statusFromErrno(errno, "inet_ntop() failed");
|
||||
}
|
||||
return std::string(out.data());
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
54
staticlibs/netd/libnetdutils/SocketOption.cpp
Normal file
54
staticlibs/netd/libnetdutils/SocketOption.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 "netdutils/SocketOption.h"
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/socket.h>
|
||||
#include <utility>
|
||||
|
||||
#include "netdutils/Syscalls.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
Status enableSockopt(Fd sock, int level, int optname) {
|
||||
auto& sys = sSyscalls.get();
|
||||
const int on = 1;
|
||||
return sys.setsockopt(sock, level, optname, &on, sizeof(on));
|
||||
}
|
||||
|
||||
Status enableTcpKeepAlives(Fd sock, unsigned idleTime, unsigned numProbes, unsigned probeInterval) {
|
||||
RETURN_IF_NOT_OK(enableSockopt(sock, SOL_SOCKET, SO_KEEPALIVE));
|
||||
|
||||
auto& sys = sSyscalls.get();
|
||||
if (idleTime != 0) {
|
||||
RETURN_IF_NOT_OK(sys.setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &idleTime, sizeof(idleTime)));
|
||||
}
|
||||
if (numProbes != 0) {
|
||||
RETURN_IF_NOT_OK(sys.setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &numProbes, sizeof(numProbes)));
|
||||
}
|
||||
if (probeInterval != 0) {
|
||||
RETURN_IF_NOT_OK(sys.setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &probeInterval,
|
||||
sizeof(probeInterval)));
|
||||
}
|
||||
|
||||
return status::ok;
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
45
staticlibs/netd/libnetdutils/Status.cpp
Normal file
45
staticlibs/netd/libnetdutils/Status.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 "netdutils/Status.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "android-base/stringprintf.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
Status statusFromErrno(int err, const std::string& msg) {
|
||||
return Status(err, base::StringPrintf("[%s] : %s", strerror(err), msg.c_str()));
|
||||
}
|
||||
|
||||
bool equalToErrno(const Status& status, int err) {
|
||||
return status.code() == err;
|
||||
}
|
||||
|
||||
std::string toString(const Status& status) {
|
||||
std::stringstream ss;
|
||||
ss << status;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Status& s) {
|
||||
return os << "Status[code: " << s.code() << ", msg: \"" << s.msg() << "\"]";
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
105
staticlibs/netd/libnetdutils/StatusTest.cpp
Normal file
105
staticlibs/netd/libnetdutils/StatusTest.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 "netdutils/Status.h"
|
||||
#include "netdutils/StatusOr.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
namespace {
|
||||
|
||||
TEST(StatusTest, valueSemantics) {
|
||||
// Default constructor
|
||||
EXPECT_EQ(status::ok, Status());
|
||||
|
||||
// Copy constructor
|
||||
Status status1(1);
|
||||
Status status2(status1); // NOLINT(performance-unnecessary-copy-initialization)
|
||||
EXPECT_EQ(1, status2.code());
|
||||
|
||||
// Copy assignment
|
||||
Status status3;
|
||||
status3 = status2;
|
||||
EXPECT_EQ(1, status3.code());
|
||||
|
||||
// Same with const objects
|
||||
const Status status4(4);
|
||||
const Status status5(status4); // NOLINT(performance-unnecessary-copy-initialization)
|
||||
Status status6;
|
||||
status6 = status5;
|
||||
EXPECT_EQ(4, status6.code());
|
||||
}
|
||||
|
||||
TEST(StatusTest, errorMessages) {
|
||||
Status s(42, "for tea too");
|
||||
EXPECT_EQ(42, s.code());
|
||||
EXPECT_FALSE(s.ok());
|
||||
EXPECT_EQ(s.msg(), "for tea too");
|
||||
}
|
||||
|
||||
TEST(StatusOrTest, moveSemantics) {
|
||||
// Status objects should be cheaply movable.
|
||||
EXPECT_TRUE(std::is_nothrow_move_constructible<Status>::value);
|
||||
EXPECT_TRUE(std::is_nothrow_move_assignable<Status>::value);
|
||||
|
||||
// Should move from a temporary Status (twice)
|
||||
Status s(Status(Status(42, "move me")));
|
||||
EXPECT_EQ(42, s.code());
|
||||
EXPECT_EQ(s.msg(), "move me");
|
||||
|
||||
Status s2(666, "EDAEMON");
|
||||
EXPECT_NE(s, s2);
|
||||
s = s2; // Invokes the move-assignment operator.
|
||||
EXPECT_EQ(666, s.code());
|
||||
EXPECT_EQ(s.msg(), "EDAEMON");
|
||||
EXPECT_EQ(s, s2);
|
||||
|
||||
// A moved-from Status can be re-used.
|
||||
s2 = s;
|
||||
|
||||
// Now both objects are valid.
|
||||
EXPECT_EQ(666, s.code());
|
||||
EXPECT_EQ(s.msg(), "EDAEMON");
|
||||
EXPECT_EQ(s, s2);
|
||||
}
|
||||
|
||||
TEST(StatusTest, ignoredStatus) {
|
||||
statusFromErrno(ENOTTY, "Not a typewriter, what did you expect?").ignoreError();
|
||||
}
|
||||
|
||||
TEST(StatusOrTest, ostream) {
|
||||
{
|
||||
StatusOr<int> so(11);
|
||||
std::stringstream ss;
|
||||
ss << so;
|
||||
// TODO: Fix StatusOr to optionally output "value:".
|
||||
EXPECT_EQ("StatusOr[status: Status[code: 0, msg: \"\"]]", ss.str());
|
||||
}
|
||||
{
|
||||
StatusOr<int> err(status::undefined);
|
||||
std::stringstream ss;
|
||||
ss << err;
|
||||
EXPECT_EQ("StatusOr[status: Status[code: 2147483647, msg: \"undefined\"]]", ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
265
staticlibs/netd/libnetdutils/Syscalls.cpp
Normal file
265
staticlibs/netd/libnetdutils/Syscalls.cpp
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 "netdutils/Syscalls.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
namespace {
|
||||
|
||||
// Retry syscall fn as long as it returns -1 with errno == EINTR
|
||||
template <typename FnT, typename... Params>
|
||||
typename std::result_of<FnT(Params...)>::type syscallRetry(FnT fn, Params&&... params) {
|
||||
auto rv = fn(std::forward<Params>(params)...);
|
||||
while ((rv == -1) && (errno == EINTR)) {
|
||||
rv = fn(std::forward<Params>(params)...);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Production implementation of Syscalls that forwards to libc syscalls.
|
||||
class RealSyscalls final : public Syscalls {
|
||||
public:
|
||||
~RealSyscalls() override = default;
|
||||
|
||||
StatusOr<UniqueFd> open(const std::string& pathname, int flags, mode_t mode) const override {
|
||||
UniqueFd fd(::open(pathname.c_str(), flags, mode));
|
||||
if (!isWellFormed(fd)) {
|
||||
return statusFromErrno(errno, "open(\"" + pathname + "\"...) failed");
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
StatusOr<UniqueFd> socket(int domain, int type, int protocol) const override {
|
||||
UniqueFd sock(::socket(domain, type, protocol));
|
||||
if (!isWellFormed(sock)) {
|
||||
return statusFromErrno(errno, "socket() failed");
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
Status getsockname(Fd sock, sockaddr* addr, socklen_t* addrlen) const override {
|
||||
auto rv = ::getsockname(sock.get(), addr, addrlen);
|
||||
if (rv == -1) {
|
||||
return statusFromErrno(errno, "getsockname() failed");
|
||||
}
|
||||
return status::ok;
|
||||
}
|
||||
|
||||
Status getsockopt(Fd sock, int level, int optname, void* optval,
|
||||
socklen_t* optlen) const override {
|
||||
auto rv = ::getsockopt(sock.get(), level, optname, optval, optlen);
|
||||
if (rv == -1) {
|
||||
return statusFromErrno(errno, "getsockopt() failed");
|
||||
}
|
||||
return status::ok;
|
||||
}
|
||||
|
||||
Status setsockopt(Fd sock, int level, int optname, const void* optval,
|
||||
socklen_t optlen) const override {
|
||||
auto rv = ::setsockopt(sock.get(), level, optname, optval, optlen);
|
||||
if (rv == -1) {
|
||||
return statusFromErrno(errno, "setsockopt() failed");
|
||||
}
|
||||
return status::ok;
|
||||
}
|
||||
|
||||
Status bind(Fd sock, const sockaddr* addr, socklen_t addrlen) const override {
|
||||
auto rv = ::bind(sock.get(), addr, addrlen);
|
||||
if (rv == -1) {
|
||||
return statusFromErrno(errno, "bind() failed");
|
||||
}
|
||||
return status::ok;
|
||||
}
|
||||
|
||||
Status connect(Fd sock, const sockaddr* addr, socklen_t addrlen) const override {
|
||||
auto rv = syscallRetry(::connect, sock.get(), addr, addrlen);
|
||||
if (rv == -1) {
|
||||
return statusFromErrno(errno, "connect() failed");
|
||||
}
|
||||
return status::ok;
|
||||
}
|
||||
|
||||
StatusOr<ifreq> ioctl(Fd sock, unsigned long request, ifreq* ifr) const override {
|
||||
auto rv = ::ioctl(sock.get(), request, ifr);
|
||||
if (rv == -1) {
|
||||
return statusFromErrno(errno, "ioctl() failed");
|
||||
}
|
||||
return *ifr;
|
||||
}
|
||||
|
||||
StatusOr<UniqueFd> eventfd(unsigned int initval, int flags) const override {
|
||||
UniqueFd fd(::eventfd(initval, flags));
|
||||
if (!isWellFormed(fd)) {
|
||||
return statusFromErrno(errno, "eventfd() failed");
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
StatusOr<int> ppoll(pollfd* fds, nfds_t nfds, double timeout) const override {
|
||||
timespec ts = {};
|
||||
ts.tv_sec = timeout;
|
||||
ts.tv_nsec = (timeout - ts.tv_sec) * 1e9;
|
||||
auto rv = syscallRetry(::ppoll, fds, nfds, &ts, nullptr);
|
||||
if (rv == -1) {
|
||||
return statusFromErrno(errno, "ppoll() failed");
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
StatusOr<size_t> writev(Fd fd, const std::vector<iovec>& iov) const override {
|
||||
auto rv = syscallRetry(::writev, fd.get(), iov.data(), iov.size());
|
||||
if (rv == -1) {
|
||||
return statusFromErrno(errno, "writev() failed");
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
StatusOr<size_t> write(Fd fd, const Slice buf) const override {
|
||||
auto rv = syscallRetry(::write, fd.get(), buf.base(), buf.size());
|
||||
if (rv == -1) {
|
||||
return statusFromErrno(errno, "write() failed");
|
||||
}
|
||||
return static_cast<size_t>(rv);
|
||||
}
|
||||
|
||||
StatusOr<Slice> read(Fd fd, const Slice buf) const override {
|
||||
auto rv = syscallRetry(::read, fd.get(), buf.base(), buf.size());
|
||||
if (rv == -1) {
|
||||
return statusFromErrno(errno, "read() failed");
|
||||
}
|
||||
return Slice(buf.base(), rv);
|
||||
}
|
||||
|
||||
StatusOr<size_t> sendto(Fd sock, const Slice buf, int flags, const sockaddr* dst,
|
||||
socklen_t dstlen) const override {
|
||||
auto rv = syscallRetry(::sendto, sock.get(), buf.base(), buf.size(), flags, dst, dstlen);
|
||||
if (rv == -1) {
|
||||
return statusFromErrno(errno, "sendto() failed");
|
||||
}
|
||||
return static_cast<size_t>(rv);
|
||||
}
|
||||
|
||||
StatusOr<Slice> recvfrom(Fd sock, const Slice dst, int flags, sockaddr* src,
|
||||
socklen_t* srclen) const override {
|
||||
auto rv = syscallRetry(::recvfrom, sock.get(), dst.base(), dst.size(), flags, src, srclen);
|
||||
if (rv == -1) {
|
||||
return statusFromErrno(errno, "recvfrom() failed");
|
||||
}
|
||||
if (rv == 0) {
|
||||
return status::eof;
|
||||
}
|
||||
return take(dst, rv);
|
||||
}
|
||||
|
||||
Status shutdown(Fd fd, int how) const override {
|
||||
auto rv = ::shutdown(fd.get(), how);
|
||||
if (rv == -1) {
|
||||
return statusFromErrno(errno, "shutdown() failed");
|
||||
}
|
||||
return status::ok;
|
||||
}
|
||||
|
||||
Status close(Fd fd) const override {
|
||||
auto rv = ::close(fd.get());
|
||||
if (rv == -1) {
|
||||
return statusFromErrno(errno, "close() failed");
|
||||
}
|
||||
return status::ok;
|
||||
}
|
||||
|
||||
StatusOr<UniqueFile> fopen(const std::string& path, const std::string& mode) const override {
|
||||
UniqueFile file(::fopen(path.c_str(), mode.c_str()));
|
||||
if (file == nullptr) {
|
||||
return statusFromErrno(errno, "fopen(\"" + path + "\", \"" + mode + "\") failed");
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
StatusOr<pid_t> fork() const override {
|
||||
pid_t rv = ::fork();
|
||||
if (rv == -1) {
|
||||
return statusFromErrno(errno, "fork() failed");
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
StatusOr<int> vfprintf(FILE* file, const char* format, va_list ap) const override {
|
||||
auto rv = ::vfprintf(file, format, ap);
|
||||
if (rv == -1) {
|
||||
return statusFromErrno(errno, "vfprintf() failed");
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
StatusOr<int> vfscanf(FILE* file, const char* format, va_list ap) const override {
|
||||
auto rv = ::vfscanf(file, format, ap);
|
||||
if (rv == -1) {
|
||||
return statusFromErrno(errno, "vfscanf() failed");
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
Status fclose(FILE* file) const override {
|
||||
auto rv = ::fclose(file);
|
||||
if (rv == -1) {
|
||||
return statusFromErrno(errno, "fclose() failed");
|
||||
}
|
||||
return status::ok;
|
||||
}
|
||||
};
|
||||
|
||||
SyscallsHolder::~SyscallsHolder() {
|
||||
delete &get();
|
||||
}
|
||||
|
||||
Syscalls& SyscallsHolder::get() {
|
||||
while (true) {
|
||||
// memory_order_relaxed gives the compiler and hardware more
|
||||
// freedom. If we get a stale value (this should only happen
|
||||
// early in the execution of a program) the exchange code below
|
||||
// will loop until we get the most current value.
|
||||
auto* syscalls = mSyscalls.load(std::memory_order_relaxed);
|
||||
// Common case returns existing syscalls
|
||||
if (syscalls) {
|
||||
return *syscalls;
|
||||
}
|
||||
|
||||
// This code will execute on first get()
|
||||
std::unique_ptr<Syscalls> tmp(new RealSyscalls());
|
||||
Syscalls* expected = nullptr;
|
||||
bool success = mSyscalls.compare_exchange_strong(expected, tmp.get());
|
||||
if (success) {
|
||||
// Ownership was transferred to mSyscalls already, must release()
|
||||
return *tmp.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Syscalls& SyscallsHolder::swap(Syscalls& syscalls) {
|
||||
return *mSyscalls.exchange(&syscalls);
|
||||
}
|
||||
|
||||
SyscallsHolder sSyscalls;
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
202
staticlibs/netd/libnetdutils/SyscallsTest.cpp
Normal file
202
staticlibs/netd/libnetdutils/SyscallsTest.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 <array>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "netdutils/Handle.h"
|
||||
#include "netdutils/Math.h"
|
||||
#include "netdutils/MockSyscalls.h"
|
||||
#include "netdutils/Netfilter.h"
|
||||
#include "netdutils/Netlink.h"
|
||||
#include "netdutils/Slice.h"
|
||||
#include "netdutils/Status.h"
|
||||
#include "netdutils/StatusOr.h"
|
||||
#include "netdutils/Syscalls.h"
|
||||
|
||||
using testing::_;
|
||||
using testing::ByMove;
|
||||
using testing::Invoke;
|
||||
using testing::Return;
|
||||
using testing::StrictMock;
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
class SyscallsTest : public testing::Test {
|
||||
protected:
|
||||
StrictMock<ScopedMockSyscalls> mSyscalls;
|
||||
};
|
||||
|
||||
TEST(syscalls, scopedMock) {
|
||||
auto& old = sSyscalls.get();
|
||||
{
|
||||
StrictMock<ScopedMockSyscalls> s;
|
||||
EXPECT_EQ(&s, &sSyscalls.get());
|
||||
}
|
||||
EXPECT_EQ(&old, &sSyscalls.get());
|
||||
}
|
||||
|
||||
TEST_F(SyscallsTest, open) {
|
||||
const char kPath[] = "/test/path/please/ignore";
|
||||
constexpr Fd kFd(40);
|
||||
constexpr int kFlags = 883;
|
||||
constexpr mode_t kMode = 37373;
|
||||
const auto& sys = sSyscalls.get();
|
||||
EXPECT_CALL(mSyscalls, open(kPath, kFlags, kMode)).WillOnce(Return(ByMove(UniqueFd(kFd))));
|
||||
EXPECT_CALL(mSyscalls, close(kFd)).WillOnce(Return(status::ok));
|
||||
auto result = sys.open(kPath, kFlags, kMode);
|
||||
EXPECT_EQ(status::ok, result.status());
|
||||
EXPECT_EQ(kFd, result.value());
|
||||
}
|
||||
|
||||
TEST_F(SyscallsTest, getsockname) {
|
||||
constexpr Fd kFd(40);
|
||||
sockaddr_nl expected = {};
|
||||
auto& sys = sSyscalls.get();
|
||||
|
||||
// Success
|
||||
EXPECT_CALL(mSyscalls, getsockname(kFd, _, _))
|
||||
.WillOnce(Invoke([expected](Fd, sockaddr* addr, socklen_t* addrlen) {
|
||||
memcpy(addr, &expected, sizeof(expected));
|
||||
EXPECT_EQ(*addrlen, static_cast<socklen_t>(sizeof(expected)));
|
||||
return status::ok;
|
||||
}));
|
||||
const auto result = sys.getsockname<sockaddr_nl>(kFd);
|
||||
EXPECT_TRUE(isOk(result));
|
||||
EXPECT_EQ(expected, result.value());
|
||||
|
||||
// Failure
|
||||
const Status kError = statusFromErrno(EINVAL, "test");
|
||||
EXPECT_CALL(mSyscalls, getsockname(kFd, _, _)).WillOnce(Return(kError));
|
||||
EXPECT_EQ(kError, sys.getsockname<sockaddr_nl>(kFd).status());
|
||||
}
|
||||
|
||||
TEST_F(SyscallsTest, setsockopt) {
|
||||
constexpr Fd kFd(40);
|
||||
constexpr int kLevel = 50;
|
||||
constexpr int kOptname = 70;
|
||||
sockaddr_nl expected = {};
|
||||
auto& sys = sSyscalls.get();
|
||||
|
||||
// Success
|
||||
EXPECT_CALL(mSyscalls, setsockopt(kFd, kLevel, kOptname, &expected, sizeof(expected)))
|
||||
.WillOnce(Return(status::ok));
|
||||
EXPECT_EQ(status::ok, sys.setsockopt(kFd, kLevel, kOptname, expected));
|
||||
|
||||
// Failure
|
||||
const Status kError = statusFromErrno(EINVAL, "test");
|
||||
EXPECT_CALL(mSyscalls, setsockopt(kFd, kLevel, kOptname, &expected, sizeof(expected)))
|
||||
.WillOnce(Return(kError));
|
||||
EXPECT_EQ(kError, sys.setsockopt(kFd, kLevel, kOptname, expected));
|
||||
}
|
||||
|
||||
TEST_F(SyscallsTest, getsockopt) {
|
||||
constexpr Fd kFd(40);
|
||||
constexpr int kLevel = 50;
|
||||
constexpr int kOptname = 70;
|
||||
sockaddr_nl expected = {};
|
||||
socklen_t optLen = 0;
|
||||
auto& sys = sSyscalls.get();
|
||||
|
||||
// Success
|
||||
EXPECT_CALL(mSyscalls, getsockopt(kFd, kLevel, kOptname, &expected, &optLen))
|
||||
.WillOnce(Return(status::ok));
|
||||
EXPECT_EQ(status::ok, sys.getsockopt(kFd, kLevel, kOptname, &expected, &optLen));
|
||||
|
||||
// Failure
|
||||
const Status kError = statusFromErrno(EINVAL, "test");
|
||||
EXPECT_CALL(mSyscalls, getsockopt(kFd, kLevel, kOptname, &expected, &optLen))
|
||||
.WillOnce(Return(kError));
|
||||
EXPECT_EQ(kError, sys.getsockopt(kFd, kLevel, kOptname, &expected, &optLen));
|
||||
}
|
||||
|
||||
TEST_F(SyscallsTest, bind) {
|
||||
constexpr Fd kFd(40);
|
||||
sockaddr_nl expected = {};
|
||||
auto& sys = sSyscalls.get();
|
||||
|
||||
// Success
|
||||
EXPECT_CALL(mSyscalls, bind(kFd, asSockaddrPtr(&expected), sizeof(expected)))
|
||||
.WillOnce(Return(status::ok));
|
||||
EXPECT_EQ(status::ok, sys.bind(kFd, expected));
|
||||
|
||||
// Failure
|
||||
const Status kError = statusFromErrno(EINVAL, "test");
|
||||
EXPECT_CALL(mSyscalls, bind(kFd, asSockaddrPtr(&expected), sizeof(expected)))
|
||||
.WillOnce(Return(kError));
|
||||
EXPECT_EQ(kError, sys.bind(kFd, expected));
|
||||
}
|
||||
|
||||
TEST_F(SyscallsTest, connect) {
|
||||
constexpr Fd kFd(40);
|
||||
sockaddr_nl expected = {};
|
||||
auto& sys = sSyscalls.get();
|
||||
|
||||
// Success
|
||||
EXPECT_CALL(mSyscalls, connect(kFd, asSockaddrPtr(&expected), sizeof(expected)))
|
||||
.WillOnce(Return(status::ok));
|
||||
EXPECT_EQ(status::ok, sys.connect(kFd, expected));
|
||||
|
||||
// Failure
|
||||
const Status kError = statusFromErrno(EINVAL, "test");
|
||||
EXPECT_CALL(mSyscalls, connect(kFd, asSockaddrPtr(&expected), sizeof(expected)))
|
||||
.WillOnce(Return(kError));
|
||||
EXPECT_EQ(kError, sys.connect(kFd, expected));
|
||||
}
|
||||
|
||||
TEST_F(SyscallsTest, sendto) {
|
||||
constexpr Fd kFd(40);
|
||||
constexpr int kFlags = 0;
|
||||
std::array<char, 10> payload;
|
||||
const auto slice = makeSlice(payload);
|
||||
sockaddr_nl expected = {};
|
||||
auto& sys = sSyscalls.get();
|
||||
|
||||
// Success
|
||||
EXPECT_CALL(mSyscalls, sendto(kFd, slice, kFlags, asSockaddrPtr(&expected), sizeof(expected)))
|
||||
.WillOnce(Return(slice.size()));
|
||||
EXPECT_EQ(status::ok, sys.sendto(kFd, slice, kFlags, expected));
|
||||
}
|
||||
|
||||
TEST_F(SyscallsTest, recvfrom) {
|
||||
constexpr Fd kFd(40);
|
||||
constexpr int kFlags = 0;
|
||||
std::array<char, 10> payload;
|
||||
const auto dst = makeSlice(payload);
|
||||
const auto used = take(dst, 8);
|
||||
sockaddr_nl expected = {};
|
||||
auto& sys = sSyscalls.get();
|
||||
|
||||
// Success
|
||||
EXPECT_CALL(mSyscalls, recvfrom(kFd, dst, kFlags, _, _))
|
||||
.WillOnce(Invoke(
|
||||
[expected, used](Fd, const Slice, int, sockaddr* src, socklen_t* srclen) {
|
||||
*srclen = sizeof(expected);
|
||||
memcpy(src, &expected, *srclen);
|
||||
return used;
|
||||
}));
|
||||
auto result = sys.recvfrom<sockaddr_nl>(kFd, dst, kFlags);
|
||||
EXPECT_EQ(status::ok, result.status());
|
||||
EXPECT_EQ(used, result.value().first);
|
||||
EXPECT_EQ(expected, result.value().second);
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
122
staticlibs/netd/libnetdutils/ThreadUtilTest.cpp
Normal file
122
staticlibs/netd/libnetdutils/ThreadUtilTest.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 <string>
|
||||
|
||||
#include <android-base/expected.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <netdutils/ThreadUtil.h>
|
||||
|
||||
namespace android::netdutils {
|
||||
|
||||
namespace {
|
||||
|
||||
android::base::expected<std::string, int> getThreadName() {
|
||||
char name[16] = {};
|
||||
if (const int ret = pthread_getname_np(pthread_self(), name, sizeof(name)); ret != 0) {
|
||||
return android::base::unexpected(ret);
|
||||
}
|
||||
return std::string(name);
|
||||
}
|
||||
|
||||
class NoopRun {
|
||||
public:
|
||||
explicit NoopRun(const std::string& name = "") : mName(name) { instanceNum++; }
|
||||
|
||||
// Destructor happens in the thread.
|
||||
~NoopRun() {
|
||||
if (checkName) {
|
||||
auto expected = getThreadName();
|
||||
EXPECT_TRUE(expected.has_value());
|
||||
EXPECT_EQ(mExpectedName, expected.value());
|
||||
}
|
||||
instanceNum--;
|
||||
}
|
||||
|
||||
void run() {}
|
||||
|
||||
std::string threadName() { return mName; }
|
||||
|
||||
// Set the expected thread name which will be used to check if it matches the actual thread
|
||||
// name which is returned from the system call. The check will happen in the destructor.
|
||||
void setExpectedName(const std::string& expectedName) {
|
||||
checkName = true;
|
||||
mExpectedName = expectedName;
|
||||
}
|
||||
|
||||
static bool waitForAllReleased(int timeoutMs) {
|
||||
constexpr int intervalMs = 20;
|
||||
int limit = timeoutMs / intervalMs;
|
||||
for (int i = 1; i < limit; i++) {
|
||||
if (instanceNum == 0) {
|
||||
return true;
|
||||
}
|
||||
usleep(intervalMs * 1000);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// To track how many instances are alive.
|
||||
static std::atomic<int> instanceNum;
|
||||
|
||||
private:
|
||||
std::string mName;
|
||||
std::string mExpectedName;
|
||||
bool checkName = false;
|
||||
};
|
||||
|
||||
std::atomic<int> NoopRun::instanceNum;
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(ThreadUtilTest, objectReleased) {
|
||||
NoopRun::instanceNum = 0;
|
||||
NoopRun* obj = new NoopRun();
|
||||
EXPECT_EQ(1, NoopRun::instanceNum);
|
||||
threadLaunch(obj);
|
||||
|
||||
// Wait for the object released along with the thread exited.
|
||||
EXPECT_TRUE(NoopRun::waitForAllReleased(1000));
|
||||
EXPECT_EQ(0, NoopRun::instanceNum);
|
||||
}
|
||||
|
||||
TEST(ThreadUtilTest, SetThreadName) {
|
||||
NoopRun::instanceNum = 0;
|
||||
|
||||
// Test thread name empty.
|
||||
NoopRun* obj1 = new NoopRun();
|
||||
obj1->setExpectedName("");
|
||||
|
||||
// Test normal case.
|
||||
NoopRun* obj2 = new NoopRun("TestName");
|
||||
obj2->setExpectedName("TestName");
|
||||
|
||||
// Test thread name too long.
|
||||
std::string name("TestNameTooooLong");
|
||||
NoopRun* obj3 = new NoopRun(name);
|
||||
obj3->setExpectedName(name.substr(0, 15));
|
||||
|
||||
// Thread names are examined in their destructors.
|
||||
EXPECT_EQ(3, NoopRun::instanceNum);
|
||||
threadLaunch(obj1);
|
||||
threadLaunch(obj2);
|
||||
threadLaunch(obj3);
|
||||
|
||||
EXPECT_TRUE(NoopRun::waitForAllReleased(1000));
|
||||
EXPECT_EQ(0, NoopRun::instanceNum);
|
||||
}
|
||||
|
||||
} // namespace android::netdutils
|
||||
38
staticlibs/netd/libnetdutils/UniqueFd.cpp
Normal file
38
staticlibs/netd/libnetdutils/UniqueFd.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 <algorithm>
|
||||
|
||||
#include "netdutils/UniqueFd.h"
|
||||
#include "netdutils/Syscalls.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
void UniqueFd::reset(Fd fd) {
|
||||
auto& sys = sSyscalls.get();
|
||||
std::swap(fd, mFd);
|
||||
if (isWellFormed(fd)) {
|
||||
expectOk(sys.close(fd));
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const UniqueFd& fd) {
|
||||
return os << "UniqueFd[" << static_cast<Fd>(fd) << "]";
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
31
staticlibs/netd/libnetdutils/UniqueFile.cpp
Normal file
31
staticlibs/netd/libnetdutils/UniqueFile.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 <algorithm>
|
||||
|
||||
#include "netdutils/Syscalls.h"
|
||||
#include "netdutils/UniqueFile.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
void UniqueFileDtor::operator()(FILE* file) const {
|
||||
const auto& sys = sSyscalls.get();
|
||||
sys.fclose(file).ignoreError();
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
153
staticlibs/netd/libnetdutils/include/netdutils/BackoffSequence.h
Normal file
153
staticlibs/netd/libnetdutils/include/netdutils/BackoffSequence.h
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETDUTILS_BACKOFFSEQUENCE_H
|
||||
#define NETDUTILS_BACKOFFSEQUENCE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <limits>
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
// Encapsulate some RFC 3315 section 14 -style backoff mechanics.
|
||||
//
|
||||
// https://tools.ietf.org/html/rfc3315#section-14
|
||||
template<typename time_type = std::chrono::seconds, typename counter_type = uint32_t>
|
||||
class BackoffSequence {
|
||||
public:
|
||||
struct Parameters {
|
||||
time_type initialRetransTime{TIME_UNITY};
|
||||
counter_type maxRetransCount{0U};
|
||||
time_type maxRetransTime{TIME_ZERO};
|
||||
time_type maxRetransDuration{TIME_ZERO};
|
||||
time_type endOfSequenceIndicator{TIME_ZERO};
|
||||
};
|
||||
|
||||
BackoffSequence() : BackoffSequence(Parameters{}) {}
|
||||
BackoffSequence(const BackoffSequence &) = default;
|
||||
BackoffSequence(BackoffSequence &&) = default;
|
||||
BackoffSequence& operator=(const BackoffSequence &) = default;
|
||||
BackoffSequence& operator=(BackoffSequence &&) = default;
|
||||
|
||||
bool hasNextTimeout() const noexcept {
|
||||
return !maxRetransCountExceed() && !maxRetransDurationExceeded();
|
||||
}
|
||||
|
||||
// Returns 0 when the sequence is exhausted.
|
||||
time_type getNextTimeout() {
|
||||
if (!hasNextTimeout()) return getEndOfSequenceIndicator();
|
||||
|
||||
mRetransTime = getNextTimeoutAfter(mRetransTime);
|
||||
|
||||
mRetransCount++;
|
||||
mTotalRetransDuration += mRetransTime;
|
||||
return mRetransTime;
|
||||
}
|
||||
|
||||
time_type getEndOfSequenceIndicator() const noexcept {
|
||||
return mParams.endOfSequenceIndicator;
|
||||
}
|
||||
|
||||
class Builder {
|
||||
public:
|
||||
Builder() {}
|
||||
|
||||
constexpr Builder& withInitialRetransmissionTime(time_type irt) {
|
||||
mParams.initialRetransTime = irt;
|
||||
return *this;
|
||||
}
|
||||
constexpr Builder& withMaximumRetransmissionCount(counter_type mrc) {
|
||||
mParams.maxRetransCount = mrc;
|
||||
return *this;
|
||||
}
|
||||
constexpr Builder& withMaximumRetransmissionTime(time_type mrt) {
|
||||
mParams.maxRetransTime = mrt;
|
||||
return *this;
|
||||
}
|
||||
constexpr Builder& withMaximumRetransmissionDuration(time_type mrd) {
|
||||
mParams.maxRetransDuration = mrd;
|
||||
return *this;
|
||||
}
|
||||
constexpr Builder& withEndOfSequenceIndicator(time_type eos) {
|
||||
mParams.endOfSequenceIndicator = eos;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr BackoffSequence build() const {
|
||||
return BackoffSequence(mParams);
|
||||
}
|
||||
|
||||
private:
|
||||
Parameters mParams;
|
||||
};
|
||||
|
||||
private:
|
||||
static constexpr int PER_ITERATION_SCALING_FACTOR = 2;
|
||||
static constexpr time_type TIME_ZERO = time_type();
|
||||
static constexpr time_type TIME_UNITY = time_type(1);
|
||||
|
||||
constexpr BackoffSequence(const struct Parameters ¶ms)
|
||||
: mParams(params),
|
||||
mRetransCount(0),
|
||||
mRetransTime(TIME_ZERO),
|
||||
mTotalRetransDuration(TIME_ZERO) {}
|
||||
|
||||
constexpr bool maxRetransCountExceed() const {
|
||||
return (mParams.maxRetransCount > 0) && (mRetransCount >= mParams.maxRetransCount);
|
||||
}
|
||||
|
||||
constexpr bool maxRetransDurationExceeded() const {
|
||||
return (mParams.maxRetransDuration > TIME_ZERO) &&
|
||||
(mTotalRetransDuration >= mParams.maxRetransDuration);
|
||||
}
|
||||
|
||||
time_type getNextTimeoutAfter(time_type lastTimeout) const {
|
||||
// TODO: Support proper random jitter. Also, consider supporting some
|
||||
// per-iteration scaling factor other than doubling.
|
||||
time_type nextTimeout = (lastTimeout > TIME_ZERO)
|
||||
? PER_ITERATION_SCALING_FACTOR * lastTimeout
|
||||
: mParams.initialRetransTime;
|
||||
|
||||
// Check if overflow occurred.
|
||||
if (nextTimeout < lastTimeout) {
|
||||
nextTimeout = std::numeric_limits<time_type>::max();
|
||||
}
|
||||
|
||||
// Cap to maximum allowed, if necessary.
|
||||
if (mParams.maxRetransTime > TIME_ZERO) {
|
||||
nextTimeout = std::min(nextTimeout, mParams.maxRetransTime);
|
||||
}
|
||||
|
||||
// Don't overflow the maximum total duration.
|
||||
if (mParams.maxRetransDuration > TIME_ZERO) {
|
||||
nextTimeout = std::min(nextTimeout, mParams.maxRetransDuration - lastTimeout);
|
||||
}
|
||||
return nextTimeout;
|
||||
}
|
||||
|
||||
const Parameters mParams;
|
||||
counter_type mRetransCount;
|
||||
time_type mRetransTime;
|
||||
time_type mTotalRetransDuration;
|
||||
};
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif /* NETDUTILS_BACKOFFSEQUENCE_H */
|
||||
68
staticlibs/netd/libnetdutils/include/netdutils/DumpWriter.h
Normal file
68
staticlibs/netd/libnetdutils/include/netdutils/DumpWriter.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETDUTILS_DUMPWRITER_H_
|
||||
#define NETDUTILS_DUMPWRITER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
class DumpWriter {
|
||||
public:
|
||||
DumpWriter(int fd);
|
||||
|
||||
void incIndent();
|
||||
void decIndent();
|
||||
|
||||
void println(const std::string& line);
|
||||
template <size_t n>
|
||||
void println(const char line[n]) {
|
||||
println(std::string(line));
|
||||
}
|
||||
// Hint to the compiler that it should apply printf validation of
|
||||
// arguments (beginning at position 3) of the format (specified in
|
||||
// position 2). Note that position 1 is the implicit "this" argument.
|
||||
void println(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3)));
|
||||
void blankline() { println(""); }
|
||||
|
||||
private:
|
||||
uint8_t mIndentLevel;
|
||||
int mFd;
|
||||
};
|
||||
|
||||
class ScopedIndent {
|
||||
public:
|
||||
ScopedIndent() = delete;
|
||||
ScopedIndent(const ScopedIndent&) = delete;
|
||||
ScopedIndent(ScopedIndent&&) = delete;
|
||||
explicit ScopedIndent(DumpWriter& dw) : mDw(dw) { mDw.incIndent(); }
|
||||
~ScopedIndent() { mDw.decIndent(); }
|
||||
ScopedIndent& operator=(const ScopedIndent&) = delete;
|
||||
ScopedIndent& operator=(ScopedIndent&&) = delete;
|
||||
|
||||
// TODO: consider additional {inc,dec}Indent methods and a counter that
|
||||
// can be used to unwind all pending increments on exit.
|
||||
|
||||
private:
|
||||
DumpWriter& mDw;
|
||||
};
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif // NETDUTILS_DUMPWRITER_H_
|
||||
54
staticlibs/netd/libnetdutils/include/netdutils/Fd.h
Normal file
54
staticlibs/netd/libnetdutils/include/netdutils/Fd.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETUTILS_FD_H
|
||||
#define NETUTILS_FD_H
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include "netdutils/Status.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
// Strongly typed wrapper for file descriptors with value semantics.
|
||||
// This class should typically hold unowned file descriptors.
|
||||
class Fd {
|
||||
public:
|
||||
constexpr Fd() = default;
|
||||
|
||||
constexpr Fd(int fd) : mFd(fd) {}
|
||||
|
||||
int get() const { return mFd; }
|
||||
|
||||
bool operator==(const Fd& other) const { return get() == other.get(); }
|
||||
bool operator!=(const Fd& other) const { return get() != other.get(); }
|
||||
|
||||
private:
|
||||
int mFd = -1;
|
||||
};
|
||||
|
||||
// Return true if fd appears valid (non-negative)
|
||||
inline bool isWellFormed(const Fd fd) {
|
||||
return fd.get() >= 0;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Fd& fd);
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif /* NETUTILS_FD_H */
|
||||
74
staticlibs/netd/libnetdutils/include/netdutils/Handle.h
Normal file
74
staticlibs/netd/libnetdutils/include/netdutils/Handle.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETUTILS_HANDLE_H
|
||||
#define NETUTILS_HANDLE_H
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
// Opaque, strongly typed wrapper for integer-like handles.
|
||||
// Explicitly avoids implementing arithmetic operations.
|
||||
//
|
||||
// This class is intended to avoid common errors when reordering
|
||||
// arguments to functions, typos and other cases where plain integer
|
||||
// types would silently cover up the mistake.
|
||||
//
|
||||
// usage:
|
||||
// DEFINE_HANDLE(ProductId, uint64_t);
|
||||
// DEFINE_HANDLE(ThumbnailHash, uint64_t);
|
||||
// void foo(ProductId p, ThumbnailHash th) {...}
|
||||
//
|
||||
// void test() {
|
||||
// ProductId p(88);
|
||||
// ThumbnailHash th1(100), th2(200);
|
||||
//
|
||||
// foo(p, th1); <- ok!
|
||||
// foo(th1, p); <- disallowed!
|
||||
// th1 += 10; <- disallowed!
|
||||
// p = th2; <- disallowed!
|
||||
// assert(th1 != th2); <- ok!
|
||||
// }
|
||||
template <typename T, typename TagT>
|
||||
class Handle {
|
||||
public:
|
||||
constexpr Handle() = default;
|
||||
constexpr Handle(const T& value) : mValue(value) {}
|
||||
|
||||
const T get() const { return mValue; }
|
||||
|
||||
bool operator==(const Handle& that) const { return get() == that.get(); }
|
||||
bool operator!=(const Handle& that) const { return get() != that.get(); }
|
||||
|
||||
private:
|
||||
T mValue;
|
||||
};
|
||||
|
||||
#define DEFINE_HANDLE(name, type) \
|
||||
struct _##name##Tag {}; \
|
||||
using name = ::android::netdutils::Handle<type, _##name##Tag>;
|
||||
|
||||
template <typename T, typename TagT>
|
||||
inline std::ostream& operator<<(std::ostream& os, const Handle<T, TagT>& handle) {
|
||||
return os << handle.get();
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif /* NETUTILS_HANDLE_H */
|
||||
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdint.h>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include "netdutils/NetworkConstants.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
namespace internal_ {
|
||||
|
||||
// A structure to hold data for dealing with Internet addresses (IPAddress) and
|
||||
// related types such as IPSockAddr and IPPrefix.
|
||||
struct compact_ipdata {
|
||||
uint8_t family{AF_UNSPEC};
|
||||
uint8_t cidrlen{0U}; // written and read in host-byte order
|
||||
in_port_t port{0U}; // written and read in host-byte order
|
||||
uint32_t scope_id{0U};
|
||||
union {
|
||||
in_addr v4;
|
||||
in6_addr v6;
|
||||
} ip{.v6 = IN6ADDR_ANY_INIT}; // written and read in network-byte order
|
||||
|
||||
// Classes that use compact_ipdata and this method should be sure to clear
|
||||
// (i.e. zero or make uniform) any fields not relevant to the class.
|
||||
friend bool operator==(const compact_ipdata& a, const compact_ipdata& b) {
|
||||
if ((a.family != b.family) || (a.cidrlen != b.cidrlen) || (a.port != b.port) ||
|
||||
(a.scope_id != b.scope_id)) {
|
||||
return false;
|
||||
}
|
||||
switch (a.family) {
|
||||
case AF_UNSPEC:
|
||||
// After the above checks, two AF_UNSPEC objects can be
|
||||
// considered equal, for convenience.
|
||||
return true;
|
||||
case AF_INET: {
|
||||
const in_addr v4a = a.ip.v4;
|
||||
const in_addr v4b = b.ip.v4;
|
||||
return (v4a.s_addr == v4b.s_addr);
|
||||
}
|
||||
case AF_INET6: {
|
||||
const in6_addr v6a = a.ip.v6;
|
||||
const in6_addr v6b = b.ip.v6;
|
||||
return IN6_ARE_ADDR_EQUAL(&v6a, &v6b);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Classes that use compact_ipdata and this method should be sure to clear
|
||||
// (i.e. zero or make uniform) any fields not relevant to the class.
|
||||
friend bool operator!=(const compact_ipdata& a, const compact_ipdata& b) { return !(a == b); }
|
||||
|
||||
// Classes that use compact_ipdata and this method should be sure to clear
|
||||
// (i.e. zero or make uniform) any fields not relevant to the class.
|
||||
friend bool operator<(const compact_ipdata& a, const compact_ipdata& b) {
|
||||
if (a.family != b.family) return (a.family < b.family);
|
||||
switch (a.family) {
|
||||
case AF_INET: {
|
||||
const in_addr v4a = a.ip.v4;
|
||||
const in_addr v4b = b.ip.v4;
|
||||
if (v4a.s_addr != v4b.s_addr) return (ntohl(v4a.s_addr) < ntohl(v4b.s_addr));
|
||||
break;
|
||||
}
|
||||
case AF_INET6: {
|
||||
const in6_addr v6a = a.ip.v6;
|
||||
const in6_addr v6b = b.ip.v6;
|
||||
const int cmp = std::memcmp(v6a.s6_addr, v6b.s6_addr, IPV6_ADDR_LEN);
|
||||
if (cmp != 0) return cmp < 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (a.cidrlen != b.cidrlen) return (a.cidrlen < b.cidrlen);
|
||||
if (a.port != b.port) return (a.port < b.port);
|
||||
return (a.scope_id < b.scope_id);
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(AF_UNSPEC <= std::numeric_limits<uint8_t>::max(), "AF_UNSPEC value too large");
|
||||
static_assert(AF_INET <= std::numeric_limits<uint8_t>::max(), "AF_INET value too large");
|
||||
static_assert(AF_INET6 <= std::numeric_limits<uint8_t>::max(), "AF_INET6 value too large");
|
||||
static_assert(sizeof(compact_ipdata) == 24U, "compact_ipdata unexpectedly large");
|
||||
|
||||
} // namespace internal_
|
||||
|
||||
struct AddrinfoDeleter {
|
||||
void operator()(struct addrinfo* p) const {
|
||||
if (p != nullptr) {
|
||||
freeaddrinfo(p);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::unique_ptr<struct addrinfo, struct AddrinfoDeleter> ScopedAddrinfo;
|
||||
|
||||
inline bool usesScopedIds(const in6_addr& ipv6) {
|
||||
return (IN6_IS_ADDR_LINKLOCAL(&ipv6) || IN6_IS_ADDR_MC_LINKLOCAL(&ipv6));
|
||||
}
|
||||
|
||||
class IPPrefix;
|
||||
class IPSockAddr;
|
||||
|
||||
class IPAddress {
|
||||
public:
|
||||
static bool forString(const std::string& repr, IPAddress* ip);
|
||||
static IPAddress forString(const std::string& repr) {
|
||||
IPAddress ip;
|
||||
if (!forString(repr, &ip)) return IPAddress();
|
||||
return ip;
|
||||
}
|
||||
|
||||
IPAddress() = default;
|
||||
IPAddress(const IPAddress&) = default;
|
||||
IPAddress(IPAddress&&) = default;
|
||||
|
||||
explicit IPAddress(const in_addr& ipv4)
|
||||
: mData({AF_INET, IPV4_ADDR_BITS, 0U, 0U, {.v4 = ipv4}}) {}
|
||||
explicit IPAddress(const in6_addr& ipv6)
|
||||
: mData({AF_INET6, IPV6_ADDR_BITS, 0U, 0U, {.v6 = ipv6}}) {}
|
||||
IPAddress(const in6_addr& ipv6, uint32_t scope_id)
|
||||
: mData({AF_INET6,
|
||||
IPV6_ADDR_BITS,
|
||||
0U,
|
||||
// Sanity check: scoped_ids only for link-local addresses.
|
||||
usesScopedIds(ipv6) ? scope_id : 0U,
|
||||
{.v6 = ipv6}}) {}
|
||||
IPAddress(const IPAddress& ip, uint32_t scope_id) : IPAddress(ip) {
|
||||
mData.scope_id = (family() == AF_INET6 && usesScopedIds(mData.ip.v6)) ? scope_id : 0U;
|
||||
}
|
||||
|
||||
IPAddress& operator=(const IPAddress&) = default;
|
||||
IPAddress& operator=(IPAddress&&) = default;
|
||||
|
||||
constexpr sa_family_t family() const noexcept { return mData.family; }
|
||||
constexpr uint32_t scope_id() const noexcept { return mData.scope_id; }
|
||||
|
||||
std::string toString() const noexcept;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const IPAddress& ip) {
|
||||
os << ip.toString();
|
||||
return os;
|
||||
}
|
||||
friend bool operator==(const IPAddress& a, const IPAddress& b) { return (a.mData == b.mData); }
|
||||
friend bool operator!=(const IPAddress& a, const IPAddress& b) { return (a.mData != b.mData); }
|
||||
friend bool operator<(const IPAddress& a, const IPAddress& b) { return (a.mData < b.mData); }
|
||||
friend bool operator>(const IPAddress& a, const IPAddress& b) { return (b.mData < a.mData); }
|
||||
friend bool operator<=(const IPAddress& a, const IPAddress& b) { return (a < b) || (a == b); }
|
||||
friend bool operator>=(const IPAddress& a, const IPAddress& b) { return (b < a) || (a == b); }
|
||||
|
||||
private:
|
||||
friend class IPPrefix;
|
||||
friend class IPSockAddr;
|
||||
|
||||
explicit IPAddress(const internal_::compact_ipdata& ipdata) : mData(ipdata) {
|
||||
mData.port = 0U;
|
||||
switch (mData.family) {
|
||||
case AF_INET:
|
||||
mData.cidrlen = IPV4_ADDR_BITS;
|
||||
mData.scope_id = 0U;
|
||||
break;
|
||||
case AF_INET6:
|
||||
mData.cidrlen = IPV6_ADDR_BITS;
|
||||
if (usesScopedIds(ipdata.ip.v6)) mData.scope_id = ipdata.scope_id;
|
||||
break;
|
||||
default:
|
||||
mData.cidrlen = 0U;
|
||||
mData.scope_id = 0U;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
internal_::compact_ipdata mData{};
|
||||
};
|
||||
|
||||
class IPPrefix {
|
||||
public:
|
||||
static bool forString(const std::string& repr, IPPrefix* prefix);
|
||||
static IPPrefix forString(const std::string& repr) {
|
||||
IPPrefix prefix;
|
||||
if (!forString(repr, &prefix)) return IPPrefix();
|
||||
return prefix;
|
||||
}
|
||||
|
||||
IPPrefix() = default;
|
||||
IPPrefix(const IPPrefix&) = default;
|
||||
IPPrefix(IPPrefix&&) = default;
|
||||
|
||||
explicit IPPrefix(const IPAddress& ip) : mData(ip.mData) {}
|
||||
|
||||
// Truncate the IP address |ip| at length |length|. Lengths greater than
|
||||
// the address-family-relevant maximum, along with negative values, are
|
||||
// interpreted as if the address-family-relevant maximum had been given.
|
||||
IPPrefix(const IPAddress& ip, int length);
|
||||
|
||||
IPPrefix& operator=(const IPPrefix&) = default;
|
||||
IPPrefix& operator=(IPPrefix&&) = default;
|
||||
|
||||
constexpr sa_family_t family() const noexcept { return mData.family; }
|
||||
IPAddress ip() const noexcept { return IPAddress(mData); }
|
||||
in_addr addr4() const noexcept { return mData.ip.v4; }
|
||||
in6_addr addr6() const noexcept { return mData.ip.v6; }
|
||||
constexpr int length() const noexcept { return mData.cidrlen; }
|
||||
|
||||
bool isUninitialized() const noexcept;
|
||||
std::string toString() const noexcept;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const IPPrefix& prefix) {
|
||||
os << prefix.toString();
|
||||
return os;
|
||||
}
|
||||
friend bool operator==(const IPPrefix& a, const IPPrefix& b) { return (a.mData == b.mData); }
|
||||
friend bool operator!=(const IPPrefix& a, const IPPrefix& b) { return (a.mData != b.mData); }
|
||||
friend bool operator<(const IPPrefix& a, const IPPrefix& b) { return (a.mData < b.mData); }
|
||||
friend bool operator>(const IPPrefix& a, const IPPrefix& b) { return (b.mData < a.mData); }
|
||||
friend bool operator<=(const IPPrefix& a, const IPPrefix& b) { return (a < b) || (a == b); }
|
||||
friend bool operator>=(const IPPrefix& a, const IPPrefix& b) { return (b < a) || (a == b); }
|
||||
|
||||
private:
|
||||
internal_::compact_ipdata mData{};
|
||||
};
|
||||
|
||||
// An Internet socket address.
|
||||
//
|
||||
// Cannot represent other types of socket addresses (e.g. UNIX socket address, et cetera).
|
||||
class IPSockAddr {
|
||||
public:
|
||||
// TODO: static forString
|
||||
|
||||
static IPSockAddr toIPSockAddr(const std::string& repr, in_port_t port) {
|
||||
return IPSockAddr(IPAddress::forString(repr), port);
|
||||
}
|
||||
static IPSockAddr toIPSockAddr(const sockaddr& sa) {
|
||||
switch (sa.sa_family) {
|
||||
case AF_INET:
|
||||
return IPSockAddr(*reinterpret_cast<const sockaddr_in*>(&sa));
|
||||
case AF_INET6:
|
||||
return IPSockAddr(*reinterpret_cast<const sockaddr_in6*>(&sa));
|
||||
default:
|
||||
return IPSockAddr();
|
||||
}
|
||||
}
|
||||
static IPSockAddr toIPSockAddr(const sockaddr_storage& ss) {
|
||||
return toIPSockAddr(*reinterpret_cast<const sockaddr*>(&ss));
|
||||
}
|
||||
|
||||
IPSockAddr() = default;
|
||||
IPSockAddr(const IPSockAddr&) = default;
|
||||
IPSockAddr(IPSockAddr&&) = default;
|
||||
|
||||
explicit IPSockAddr(const IPAddress& ip) : mData(ip.mData) {}
|
||||
IPSockAddr(const IPAddress& ip, in_port_t port) : mData(ip.mData) { mData.port = port; }
|
||||
explicit IPSockAddr(const sockaddr_in& ipv4sa)
|
||||
: IPSockAddr(IPAddress(ipv4sa.sin_addr), ntohs(ipv4sa.sin_port)) {}
|
||||
explicit IPSockAddr(const sockaddr_in6& ipv6sa)
|
||||
: IPSockAddr(IPAddress(ipv6sa.sin6_addr, ipv6sa.sin6_scope_id), ntohs(ipv6sa.sin6_port)) {}
|
||||
|
||||
IPSockAddr& operator=(const IPSockAddr&) = default;
|
||||
IPSockAddr& operator=(IPSockAddr&&) = default;
|
||||
|
||||
constexpr sa_family_t family() const noexcept { return mData.family; }
|
||||
IPAddress ip() const noexcept { return IPAddress(mData); }
|
||||
constexpr in_port_t port() const noexcept { return mData.port; }
|
||||
|
||||
// Implicit conversion to sockaddr_storage.
|
||||
operator sockaddr_storage() const noexcept {
|
||||
sockaddr_storage ss;
|
||||
ss.ss_family = mData.family;
|
||||
switch (mData.family) {
|
||||
case AF_INET:
|
||||
reinterpret_cast<sockaddr_in*>(&ss)->sin_addr = mData.ip.v4;
|
||||
reinterpret_cast<sockaddr_in*>(&ss)->sin_port = htons(mData.port);
|
||||
break;
|
||||
case AF_INET6:
|
||||
reinterpret_cast<sockaddr_in6*>(&ss)->sin6_addr = mData.ip.v6;
|
||||
reinterpret_cast<sockaddr_in6*>(&ss)->sin6_port = htons(mData.port);
|
||||
reinterpret_cast<sockaddr_in6*>(&ss)->sin6_scope_id = mData.scope_id;
|
||||
break;
|
||||
}
|
||||
return ss;
|
||||
}
|
||||
|
||||
std::string toString() const noexcept;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const IPSockAddr& prefix) {
|
||||
os << prefix.toString();
|
||||
return os;
|
||||
}
|
||||
friend bool operator==(const IPSockAddr& a, const IPSockAddr& b) {
|
||||
return (a.mData == b.mData);
|
||||
}
|
||||
friend bool operator!=(const IPSockAddr& a, const IPSockAddr& b) {
|
||||
return (a.mData != b.mData);
|
||||
}
|
||||
friend bool operator<(const IPSockAddr& a, const IPSockAddr& b) { return (a.mData < b.mData); }
|
||||
friend bool operator>(const IPSockAddr& a, const IPSockAddr& b) { return (b.mData < a.mData); }
|
||||
friend bool operator<=(const IPSockAddr& a, const IPSockAddr& b) { return (a < b) || (a == b); }
|
||||
friend bool operator>=(const IPSockAddr& a, const IPSockAddr& b) { return (b < a) || (a == b); }
|
||||
|
||||
private:
|
||||
internal_::compact_ipdata mData{};
|
||||
};
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
211
staticlibs/netd/libnetdutils/include/netdutils/Log.h
Normal file
211
staticlibs/netd/libnetdutils/include/netdutils/Log.h
Normal file
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETUTILS_LOG_H
|
||||
#define NETUTILS_LOG_H
|
||||
|
||||
#include <chrono>
|
||||
#include <deque>
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/thread_annotations.h>
|
||||
|
||||
#include <netdutils/Status.h>
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
class LogEntry {
|
||||
public:
|
||||
LogEntry() = default;
|
||||
LogEntry(const LogEntry&) = default;
|
||||
LogEntry(LogEntry&&) = default;
|
||||
~LogEntry() = default;
|
||||
LogEntry& operator=(const LogEntry&) = default;
|
||||
LogEntry& operator=(LogEntry&&) = default;
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
///
|
||||
// Helper methods that make it easy to build up a LogEntry message.
|
||||
// If performance becomes a factor the implementations could be inlined.
|
||||
///
|
||||
LogEntry& message(const std::string& message);
|
||||
|
||||
// For calling with __FUNCTION__.
|
||||
LogEntry& function(const std::string& function_name);
|
||||
// For calling with __PRETTY_FUNCTION__.
|
||||
LogEntry& prettyFunction(const std::string& pretty_function);
|
||||
|
||||
// Convenience methods for each of the common types of function arguments.
|
||||
LogEntry& arg(const std::string& val);
|
||||
// Intended for binary buffers, formats as hex
|
||||
LogEntry& arg(const std::vector<uint8_t>& val);
|
||||
LogEntry& arg(const std::vector<int32_t>& val);
|
||||
LogEntry& arg(const std::vector<std::string>& val);
|
||||
template <typename IntT, typename = std::enable_if_t<std::is_arithmetic_v<IntT>>>
|
||||
LogEntry& arg(IntT val) {
|
||||
mArgs.push_back(std::to_string(val));
|
||||
return *this;
|
||||
}
|
||||
// Not using a plain overload here to avoid the implicit conversion from
|
||||
// any pointer to bool, which causes string literals to print as 'true'.
|
||||
template <>
|
||||
LogEntry& arg<>(bool val);
|
||||
|
||||
template <typename... Args>
|
||||
LogEntry& args(const Args&... a) {
|
||||
// Cleverness ahead: we throw away the initializer_list filled with
|
||||
// zeroes, all we care about is calling arg() for each argument.
|
||||
(void) std::initializer_list<int>{(arg(a), 0)...};
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Some things can return more than one value, or have multiple output
|
||||
// parameters, so each of these adds to the mReturns vector.
|
||||
LogEntry& returns(const std::string& rval);
|
||||
LogEntry& returns(const Status& status);
|
||||
LogEntry& returns(bool rval);
|
||||
template <class T>
|
||||
LogEntry& returns(T val) {
|
||||
mReturns.push_back(std::to_string(val));
|
||||
return *this;
|
||||
}
|
||||
|
||||
LogEntry& withUid(uid_t uid);
|
||||
|
||||
// Append the duration computed since the creation of this instance.
|
||||
LogEntry& withAutomaticDuration();
|
||||
// Append the string-ified duration computed by some other means.
|
||||
LogEntry& withDuration(const std::string& duration);
|
||||
|
||||
private:
|
||||
std::chrono::steady_clock::time_point mStart = std::chrono::steady_clock::now();
|
||||
std::string mMsg{};
|
||||
std::string mFunc{};
|
||||
std::vector<std::string> mArgs{};
|
||||
std::vector<std::string> mReturns{};
|
||||
std::string mUid{};
|
||||
std::string mDuration{};
|
||||
};
|
||||
|
||||
class Log {
|
||||
public:
|
||||
Log() = delete;
|
||||
Log(const std::string& tag) : Log(tag, MAX_ENTRIES) {}
|
||||
Log(const std::string& tag, size_t maxEntries) : mTag(tag), mMaxEntries(maxEntries) {}
|
||||
Log(const Log&) = delete;
|
||||
Log(Log&&) = delete;
|
||||
~Log();
|
||||
Log& operator=(const Log&) = delete;
|
||||
Log& operator=(Log&&) = delete;
|
||||
|
||||
LogEntry newEntry() const { return LogEntry(); }
|
||||
|
||||
// Record a log entry in internal storage only.
|
||||
void log(const std::string& entry) { record(Level::LOG, entry); }
|
||||
template <size_t n>
|
||||
void log(const char entry[n]) { log(std::string(entry)); }
|
||||
void log(const LogEntry& entry) { log(entry.toString()); }
|
||||
void log(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
|
||||
using ::android::base::StringAppendV;
|
||||
std::string result;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
StringAppendV(&result, fmt, ap);
|
||||
va_end(ap);
|
||||
log(result);
|
||||
}
|
||||
|
||||
// Record a log entry in internal storage and to ALOGI as well.
|
||||
void info(const std::string& entry) { record(Level::INFO, entry); }
|
||||
template <size_t n>
|
||||
void info(const char entry[n]) { info(std::string(entry)); }
|
||||
void info(const LogEntry& entry) { info(entry.toString()); }
|
||||
void info(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
|
||||
using ::android::base::StringAppendV;
|
||||
std::string result;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
StringAppendV(&result, fmt, ap);
|
||||
va_end(ap);
|
||||
info(result);
|
||||
}
|
||||
|
||||
// Record a log entry in internal storage and to ALOGW as well.
|
||||
void warn(const std::string& entry) { record(Level::WARN, entry); }
|
||||
template <size_t n>
|
||||
void warn(const char entry[n]) { warn(std::string(entry)); }
|
||||
void warn(const LogEntry& entry) { warn(entry.toString()); }
|
||||
void warn(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
|
||||
using ::android::base::StringAppendV;
|
||||
std::string result;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
StringAppendV(&result, fmt, ap);
|
||||
va_end(ap);
|
||||
warn(result);
|
||||
}
|
||||
|
||||
// Record a log entry in internal storage and to ALOGE as well.
|
||||
void error(const std::string& entry) { record(Level::ERROR, entry); }
|
||||
template <size_t n>
|
||||
void error(const char entry[n]) { error(std::string(entry)); }
|
||||
void error(const LogEntry& entry) { error(entry.toString()); }
|
||||
void error(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
|
||||
using ::android::base::StringAppendV;
|
||||
std::string result;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
StringAppendV(&result, fmt, ap);
|
||||
va_end(ap);
|
||||
error(result);
|
||||
}
|
||||
|
||||
// Iterates over every entry in the log in chronological order. Operates
|
||||
// on a copy of the log entries, and so perEntryFn may itself call one of
|
||||
// the logging functions if needed.
|
||||
void forEachEntry(const std::function<void(const std::string&)>& perEntryFn) const;
|
||||
|
||||
private:
|
||||
static constexpr const size_t MAX_ENTRIES = 750U;
|
||||
const std::string mTag;
|
||||
const size_t mMaxEntries;
|
||||
|
||||
// The LOG level adds an entry to mEntries but does not output the message
|
||||
// to the system log. All other levels append to mEntries and output to the
|
||||
// the system log.
|
||||
enum class Level {
|
||||
LOG,
|
||||
INFO,
|
||||
WARN,
|
||||
ERROR,
|
||||
};
|
||||
|
||||
void record(Level lvl, const std::string& entry);
|
||||
|
||||
mutable std::shared_mutex mLock;
|
||||
std::deque<const std::string> mEntries; // GUARDED_BY(mLock), when supported
|
||||
};
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif /* NETUTILS_LOG_H */
|
||||
40
staticlibs/netd/libnetdutils/include/netdutils/Math.h
Normal file
40
staticlibs/netd/libnetdutils/include/netdutils/Math.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETUTILS_MATH_H
|
||||
#define NETUTILS_MATH_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
template <class T>
|
||||
inline constexpr const T mask(const int shift) {
|
||||
return (1 << shift) - 1;
|
||||
}
|
||||
|
||||
// Align x up to the nearest integer multiple of 2^shift
|
||||
template <class T>
|
||||
inline constexpr const T align(const T& x, const int shift) {
|
||||
return (x + mask<T>(shift)) & ~mask<T>(shift);
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif /* NETUTILS_MATH_H */
|
||||
67
staticlibs/netd/libnetdutils/include/netdutils/MemBlock.h
Normal file
67
staticlibs/netd/libnetdutils/include/netdutils/MemBlock.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETUTILS_MEMBLOCK_H
|
||||
#define NETUTILS_MEMBLOCK_H
|
||||
|
||||
#include <memory>
|
||||
#include "netdutils/Slice.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
// A class to encapsulate self-deleting byte arrays while preserving access
|
||||
// to the underlying length (without the length being part of the type, e.g.
|
||||
// std::array<>). By design, the only interface to the underlying bytes is
|
||||
// via Slice, to encourage safer memory access usage.
|
||||
//
|
||||
// No thread-safety guarantees whatsoever.
|
||||
class MemBlock {
|
||||
public:
|
||||
MemBlock() : MemBlock(0U) {}
|
||||
explicit MemBlock(size_t len)
|
||||
: mData((len > 0U) ? new uint8_t[len]{} : nullptr),
|
||||
mLen(len) {}
|
||||
// Allocate memory of size src.size() and copy src into this MemBlock.
|
||||
explicit MemBlock(Slice src) : MemBlock(src.size()) {
|
||||
copy(get(), src);
|
||||
}
|
||||
|
||||
// No copy construction or assignment.
|
||||
MemBlock(const MemBlock&) = delete;
|
||||
MemBlock& operator=(const MemBlock&) = delete;
|
||||
|
||||
// Move construction and assignment are okay.
|
||||
MemBlock(MemBlock&&) = default;
|
||||
MemBlock& operator=(MemBlock&&) = default;
|
||||
|
||||
// Even though this method is const, the memory wrapped by the
|
||||
// returned Slice is mutable.
|
||||
Slice get() const noexcept { return Slice(mData.get(), mLen); }
|
||||
|
||||
// Implicit cast to Slice.
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
operator const Slice() const noexcept { return get(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<uint8_t[]> mData;
|
||||
size_t mLen;
|
||||
};
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif /* NETUTILS_MEMBLOCK_H */
|
||||
63
staticlibs/netd/libnetdutils/include/netdutils/Misc.h
Normal file
63
staticlibs/netd/libnetdutils/include/netdutils/Misc.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETUTILS_MISC_H
|
||||
#define NETUTILS_MISC_H
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
// Lookup key in map, returing a default value if key is not found
|
||||
template <typename U, typename V>
|
||||
inline const V& findWithDefault(const std::map<U, V>& map, const U& key, const V& dflt) {
|
||||
auto it = map.find(key);
|
||||
return (it == map.end()) ? dflt : it->second;
|
||||
}
|
||||
|
||||
// Movable, copiable, scoped lambda (or std::function) runner. Useful
|
||||
// for running arbitrary cleanup or logging code when exiting a scope.
|
||||
//
|
||||
// Compare to defer in golang.
|
||||
template <typename FnT>
|
||||
class Cleanup {
|
||||
public:
|
||||
Cleanup() = delete;
|
||||
explicit Cleanup(FnT fn) : mFn(fn) {}
|
||||
~Cleanup() { if (!mReleased) mFn(); }
|
||||
|
||||
void release() { mReleased = true; }
|
||||
|
||||
private:
|
||||
bool mReleased{false};
|
||||
FnT mFn;
|
||||
};
|
||||
|
||||
// Helper to make a new Cleanup. Avoids complex or impossible syntax
|
||||
// when wrapping lambdas.
|
||||
//
|
||||
// Usage:
|
||||
// auto cleanup = makeCleanup([](){ your_code_here; });
|
||||
template <typename FnT>
|
||||
Cleanup<FnT> makeCleanup(FnT fn) {
|
||||
return Cleanup<FnT>(fn);
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif /* NETUTILS_MISC_H */
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETUTILS_MOCK_SYSCALLS_H
|
||||
#define NETUTILS_MOCK_SYSCALLS_H
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "netdutils/Syscalls.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
class MockSyscalls : public Syscalls {
|
||||
public:
|
||||
virtual ~MockSyscalls() = default;
|
||||
// Use Return(ByMove(...)) to deal with movable return types.
|
||||
MOCK_CONST_METHOD3(open,
|
||||
StatusOr<UniqueFd>(const std::string& pathname, int flags, mode_t mode));
|
||||
MOCK_CONST_METHOD3(socket, StatusOr<UniqueFd>(int domain, int type, int protocol));
|
||||
MOCK_CONST_METHOD3(getsockname, Status(Fd sock, sockaddr* addr, socklen_t* addrlen));
|
||||
MOCK_CONST_METHOD5(getsockopt, Status(Fd sock, int level, int optname, void* optval,
|
||||
socklen_t *optlen));
|
||||
MOCK_CONST_METHOD5(setsockopt, Status(Fd sock, int level, int optname, const void* optval,
|
||||
socklen_t optlen));
|
||||
|
||||
MOCK_CONST_METHOD3(bind, Status(Fd sock, const sockaddr* addr, socklen_t addrlen));
|
||||
MOCK_CONST_METHOD3(connect, Status(Fd sock, const sockaddr* addr, socklen_t addrlen));
|
||||
MOCK_CONST_METHOD3(ioctl, StatusOr<ifreq>(Fd sock, unsigned long request, ifreq* ifr));
|
||||
|
||||
// Use Return(ByMove(...)) to deal with movable return types.
|
||||
MOCK_CONST_METHOD2(eventfd, StatusOr<UniqueFd>(unsigned int initval, int flags));
|
||||
MOCK_CONST_METHOD3(ppoll, StatusOr<int>(pollfd* fds, nfds_t nfds, double timeout));
|
||||
|
||||
MOCK_CONST_METHOD2(writev, StatusOr<size_t>(Fd fd, const std::vector<iovec>& iov));
|
||||
MOCK_CONST_METHOD2(write, StatusOr<size_t>(Fd fd, const Slice buf));
|
||||
MOCK_CONST_METHOD2(read, StatusOr<Slice>(Fd fd, const Slice buf));
|
||||
MOCK_CONST_METHOD5(sendto, StatusOr<size_t>(Fd sock, const Slice buf, int flags,
|
||||
const sockaddr* dst, socklen_t dstlen));
|
||||
MOCK_CONST_METHOD5(recvfrom, StatusOr<Slice>(Fd sock, const Slice dst, int flags, sockaddr* src,
|
||||
socklen_t* srclen));
|
||||
MOCK_CONST_METHOD2(shutdown, Status(Fd fd, int how));
|
||||
MOCK_CONST_METHOD1(close, Status(Fd fd));
|
||||
|
||||
MOCK_CONST_METHOD2(fopen,
|
||||
StatusOr<UniqueFile>(const std::string& path, const std::string& mode));
|
||||
MOCK_CONST_METHOD3(vfprintf, StatusOr<int>(FILE* file, const char* format, va_list ap));
|
||||
MOCK_CONST_METHOD3(vfscanf, StatusOr<int>(FILE* file, const char* format, va_list ap));
|
||||
MOCK_CONST_METHOD1(fclose, Status(FILE* file));
|
||||
MOCK_CONST_METHOD0(fork, StatusOr<pid_t>());
|
||||
};
|
||||
|
||||
// For the lifetime of this mock, replace the contents of sSyscalls
|
||||
// with a pointer to this mock. Behavior is undefined if multiple
|
||||
// ScopedMockSyscalls instances exist concurrently.
|
||||
class ScopedMockSyscalls : public MockSyscalls {
|
||||
public:
|
||||
ScopedMockSyscalls() : mOld(sSyscalls.swap(*this)) { assert((mRefcount++) == 1); }
|
||||
virtual ~ScopedMockSyscalls() {
|
||||
sSyscalls.swap(mOld);
|
||||
assert((mRefcount--) == 0);
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<int> mRefcount{0};
|
||||
Syscalls& mOld;
|
||||
};
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif /* NETUTILS_MOCK_SYSCALLS_H */
|
||||
28
staticlibs/netd/libnetdutils/include/netdutils/Netfilter.h
Normal file
28
staticlibs/netd/libnetdutils/include/netdutils/Netfilter.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETUTILS_NETFILTER_H
|
||||
#define NETUTILS_NETFILTER_H
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const nfgenmsg& msg);
|
||||
|
||||
#endif /* NETUTILS_NETFILTER_H */
|
||||
55
staticlibs/netd/libnetdutils/include/netdutils/Netlink.h
Normal file
55
staticlibs/netd/libnetdutils/include/netdutils/Netlink.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETUTILS_NETLINK_H
|
||||
#define NETUTILS_NETLINK_H
|
||||
|
||||
#include <functional>
|
||||
#include <ostream>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#include "netdutils/Slice.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
// Invoke onMsg once for each netlink message in buf. onMsg will be
|
||||
// invoked with an aligned and deserialized header along with a Slice
|
||||
// containing the message payload.
|
||||
//
|
||||
// Assume that the first message begins at offset zero within buf.
|
||||
void forEachNetlinkMessage(const Slice buf,
|
||||
const std::function<void(const nlmsghdr&, const Slice)>& onMsg);
|
||||
|
||||
// Invoke onAttr once for each netlink attribute in buf. onAttr will be
|
||||
// invoked with an aligned and deserialized header along with a Slice
|
||||
// containing the attribute payload.
|
||||
//
|
||||
// Assume that the first attribute begins at offset zero within buf.
|
||||
void forEachNetlinkAttribute(const Slice buf,
|
||||
const std::function<void(const nlattr&, const Slice)>& onAttr);
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
bool operator==(const sockaddr_nl& lhs, const sockaddr_nl& rhs);
|
||||
bool operator!=(const sockaddr_nl& lhs, const sockaddr_nl& rhs);
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const nlmsghdr& hdr);
|
||||
std::ostream& operator<<(std::ostream& os, const nlattr& attr);
|
||||
std::ostream& operator<<(std::ostream& os, const sockaddr_nl& addr);
|
||||
|
||||
#endif /* NETUTILS_NETLINK_H */
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
// See also NetworkConstants.java in frameworks/base.
|
||||
constexpr int IPV4_ADDR_LEN = 4;
|
||||
constexpr int IPV4_ADDR_BITS = 32;
|
||||
constexpr int IPV6_ADDR_LEN = 16;
|
||||
constexpr int IPV6_ADDR_BITS = 128;
|
||||
|
||||
// Referred from SHA256_DIGEST_LENGTH in boringssl
|
||||
constexpr size_t SHA256_SIZE = 32;
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETDUTILS_RESPONSECODE_H
|
||||
#define NETDUTILS_RESPONSECODE_H
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
class ResponseCode {
|
||||
// Keep in sync with
|
||||
// frameworks/base/services/java/com/android/server/NetworkManagementService.java
|
||||
public:
|
||||
// 100 series - Requestion action was initiated; expect another reply
|
||||
// before proceeding with a new command.
|
||||
// clang-format off
|
||||
static constexpr int ActionInitiated = 100;
|
||||
static constexpr int InterfaceListResult = 110;
|
||||
static constexpr int TetherInterfaceListResult = 111;
|
||||
static constexpr int TetherDnsFwdTgtListResult = 112;
|
||||
static constexpr int TtyListResult = 113;
|
||||
static constexpr int TetheringStatsListResult = 114;
|
||||
static constexpr int TetherDnsFwdNetIdResult = 115;
|
||||
|
||||
// 200 series - Requested action has been successfully completed
|
||||
static constexpr int CommandOkay = 200;
|
||||
static constexpr int TetherStatusResult = 210;
|
||||
static constexpr int IpFwdStatusResult = 211;
|
||||
static constexpr int InterfaceGetCfgResult = 213;
|
||||
// Formerly: int SoftapStatusResult = 214;
|
||||
static constexpr int UsbRNDISStatusResult = 215;
|
||||
static constexpr int InterfaceRxCounterResult = 216;
|
||||
static constexpr int InterfaceTxCounterResult = 217;
|
||||
static constexpr int InterfaceRxThrottleResult = 218;
|
||||
static constexpr int InterfaceTxThrottleResult = 219;
|
||||
static constexpr int QuotaCounterResult = 220;
|
||||
static constexpr int TetheringStatsResult = 221;
|
||||
// NOTE: keep synced with bionic/libc/dns/net/gethnamaddr.c
|
||||
static constexpr int DnsProxyQueryResult = 222;
|
||||
static constexpr int ClatdStatusResult = 223;
|
||||
|
||||
// 400 series - The command was accepted but the requested action
|
||||
// did not take place.
|
||||
static constexpr int OperationFailed = 400;
|
||||
static constexpr int DnsProxyOperationFailed = 401;
|
||||
static constexpr int ServiceStartFailed = 402;
|
||||
static constexpr int ServiceStopFailed = 403;
|
||||
|
||||
// 500 series - The command was not accepted and the requested
|
||||
// action did not take place.
|
||||
static constexpr int CommandSyntaxError = 500;
|
||||
static constexpr int CommandParameterError = 501;
|
||||
|
||||
// 600 series - Unsolicited broadcasts
|
||||
static constexpr int InterfaceChange = 600;
|
||||
static constexpr int BandwidthControl = 601;
|
||||
static constexpr int ServiceDiscoveryFailed = 602;
|
||||
static constexpr int ServiceDiscoveryServiceAdded = 603;
|
||||
static constexpr int ServiceDiscoveryServiceRemoved = 604;
|
||||
static constexpr int ServiceRegistrationFailed = 605;
|
||||
static constexpr int ServiceRegistrationSucceeded = 606;
|
||||
static constexpr int ServiceResolveFailed = 607;
|
||||
static constexpr int ServiceResolveSuccess = 608;
|
||||
static constexpr int ServiceSetHostnameFailed = 609;
|
||||
static constexpr int ServiceSetHostnameSuccess = 610;
|
||||
static constexpr int ServiceGetAddrInfoFailed = 611;
|
||||
static constexpr int ServiceGetAddrInfoSuccess = 612;
|
||||
static constexpr int InterfaceClassActivity = 613;
|
||||
static constexpr int InterfaceAddressChange = 614;
|
||||
static constexpr int InterfaceDnsInfo = 615;
|
||||
static constexpr int RouteChange = 616;
|
||||
static constexpr int StrictCleartext = 617;
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif // NETDUTILS_RESPONSECODE_H
|
||||
161
staticlibs/netd/libnetdutils/include/netdutils/Slice.h
Normal file
161
staticlibs/netd/libnetdutils/include/netdutils/Slice.h
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETUTILS_SLICE_H
|
||||
#define NETUTILS_SLICE_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <ostream>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
// Immutable wrapper for a linear region of unowned bytes.
|
||||
// Slice represents memory as a half-closed interval [base, limit).
|
||||
//
|
||||
// Note that without manually invoking the Slice() constructor, it is
|
||||
// impossible to increase the size of a slice. This guarantees that
|
||||
// applications that properly use the slice API will never access
|
||||
// memory outside of a slice.
|
||||
//
|
||||
// Note that const Slice still wraps mutable memory, however copy
|
||||
// assignment and move assignment to slice are disabled.
|
||||
class Slice {
|
||||
public:
|
||||
Slice() = default;
|
||||
|
||||
// Create a slice beginning at base and continuing to but not including limit
|
||||
Slice(void* base, void* limit) : mBase(toUint8(base)), mLimit(toUint8(limit)) {}
|
||||
|
||||
// Create a slice beginning at base and continuing for size bytes
|
||||
Slice(void* base, size_t size) : Slice(base, toUint8(base) + size) {}
|
||||
|
||||
// Return the address of the first byte in this slice
|
||||
uint8_t* base() const { return mBase; }
|
||||
|
||||
// Return the address of the first byte following this slice
|
||||
uint8_t* limit() const { return mLimit; }
|
||||
|
||||
// Return the size of this slice in bytes
|
||||
size_t size() const { return limit() - base(); }
|
||||
|
||||
// Return true if size() == 0
|
||||
bool empty() const { return base() == limit(); }
|
||||
|
||||
private:
|
||||
static uint8_t* toUint8(void* ptr) { return reinterpret_cast<uint8_t*>(ptr); }
|
||||
|
||||
uint8_t* mBase = nullptr;
|
||||
uint8_t* mLimit = nullptr;
|
||||
};
|
||||
|
||||
// Return slice representation of ref which must be a POD type
|
||||
template <typename T>
|
||||
inline const Slice makeSlice(const T& ref) {
|
||||
static_assert(std::is_pod<T>::value, "value must be a POD type");
|
||||
static_assert(!std::is_pointer<T>::value, "value must not be a pointer type");
|
||||
return {const_cast<T*>(&ref), sizeof(ref)};
|
||||
}
|
||||
|
||||
// Return slice representation of string data()
|
||||
inline const Slice makeSlice(const std::string& s) {
|
||||
using ValueT = std::string::value_type;
|
||||
return {const_cast<ValueT*>(s.data()), s.size() * sizeof(ValueT)};
|
||||
}
|
||||
|
||||
// Return slice representation of vector data()
|
||||
template <typename T>
|
||||
inline const Slice makeSlice(const std::vector<T>& v) {
|
||||
return {const_cast<T*>(v.data()), v.size() * sizeof(T)};
|
||||
}
|
||||
|
||||
// Return slice representation of array data()
|
||||
template <typename U, size_t V>
|
||||
inline const Slice makeSlice(const std::array<U, V>& a) {
|
||||
return {const_cast<U*>(a.data()), a.size() * sizeof(U)};
|
||||
}
|
||||
|
||||
// Return prefix and suffix of Slice s ending and starting at position cut
|
||||
inline std::pair<const Slice, const Slice> split(const Slice s, size_t cut) {
|
||||
const size_t tmp = std::min(cut, s.size());
|
||||
return {{s.base(), s.base() + tmp}, {s.base() + tmp, s.limit()}};
|
||||
}
|
||||
|
||||
// Return prefix of Slice s ending at position cut
|
||||
inline const Slice take(const Slice s, size_t cut) {
|
||||
return std::get<0>(split(s, cut));
|
||||
}
|
||||
|
||||
// Return suffix of Slice s starting at position cut
|
||||
inline const Slice drop(const Slice s, size_t cut) {
|
||||
return std::get<1>(split(s, cut));
|
||||
}
|
||||
|
||||
// Copy from src into dst. Bytes copied is the lesser of dst.size() and src.size()
|
||||
inline size_t copy(const Slice dst, const Slice src) {
|
||||
const auto min = std::min(dst.size(), src.size());
|
||||
memcpy(dst.base(), src.base(), min);
|
||||
return min;
|
||||
}
|
||||
|
||||
// Base case for variadic extract below
|
||||
template <typename Head>
|
||||
inline size_t extract(const Slice src, Head& head) {
|
||||
return copy(makeSlice(head), src);
|
||||
}
|
||||
|
||||
// Copy from src into one or more pointers to POD data. If src.size()
|
||||
// is less than the sum of all data pointers a suffix of data will be
|
||||
// left unmodified. Return the number of bytes copied.
|
||||
template <typename Head, typename... Tail>
|
||||
inline size_t extract(const Slice src, Head& head, Tail&... tail) {
|
||||
const auto extracted = extract(src, head);
|
||||
return extracted + extract(drop(src, extracted), tail...);
|
||||
}
|
||||
|
||||
// Return a string containing a copy of the contents of s
|
||||
std::string toString(const Slice s);
|
||||
|
||||
// Return a string containing a hexadecimal representation of the contents of s.
|
||||
// This function inserts a newline into its output every wrap bytes.
|
||||
std::string toHex(const Slice s, int wrap = INT_MAX);
|
||||
|
||||
inline bool operator==(const Slice& lhs, const Slice& rhs) {
|
||||
return (lhs.base() == rhs.base()) && (lhs.limit() == rhs.limit());
|
||||
}
|
||||
|
||||
inline bool operator!=(const Slice& lhs, const Slice& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Slice& slice);
|
||||
|
||||
// Return suffix of Slice s starting at the first match of byte c. If no matched
|
||||
// byte, return an empty Slice.
|
||||
inline const Slice findFirstMatching(const Slice s, uint8_t c) {
|
||||
uint8_t* match = (uint8_t*)memchr(s.base(), c, s.size());
|
||||
if (!match) return Slice();
|
||||
return drop(s, match - s.base());
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif /* NETUTILS_SLICE_H */
|
||||
44
staticlibs/netd/libnetdutils/include/netdutils/Socket.h
Normal file
44
staticlibs/netd/libnetdutils/include/netdutils/Socket.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETDUTILS_SOCKET_H
|
||||
#define NETDUTILS_SOCKET_H
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <string>
|
||||
|
||||
#include "netdutils/StatusOr.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
inline sockaddr* asSockaddrPtr(void* addr) {
|
||||
return reinterpret_cast<sockaddr*>(addr);
|
||||
}
|
||||
|
||||
inline const sockaddr* asSockaddrPtr(const void* addr) {
|
||||
return reinterpret_cast<const sockaddr*>(addr);
|
||||
}
|
||||
|
||||
// Return a string representation of addr or Status if there was a
|
||||
// failure during conversion.
|
||||
StatusOr<std::string> toString(const in6_addr& addr);
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif /* NETDUTILS_SOCKET_H */
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETDUTILS_SOCKETOPTION_H
|
||||
#define NETDUTILS_SOCKETOPTION_H
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <string>
|
||||
|
||||
#include "netdutils/Fd.h"
|
||||
#include "netdutils/Status.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
// Turn on simple "boolean" socket options.
|
||||
//
|
||||
// This is simple wrapper for options that are enabled via code of the form:
|
||||
//
|
||||
// int on = 1;
|
||||
// setsockopt(..., &on, sizeof(on));
|
||||
Status enableSockopt(Fd sock, int level, int optname);
|
||||
|
||||
// Turn on TCP keepalives, and set keepalive parameters for this socket.
|
||||
//
|
||||
// A parameter value of zero does not set that parameter.
|
||||
//
|
||||
// Typical system defaults are:
|
||||
//
|
||||
// idleTime (in seconds)
|
||||
// $ cat /proc/sys/net/ipv4/tcp_keepalive_time
|
||||
// 7200
|
||||
//
|
||||
// numProbes
|
||||
// $ cat /proc/sys/net/ipv4/tcp_keepalive_probes
|
||||
// 9
|
||||
//
|
||||
// probeInterval (in seconds)
|
||||
// $ cat /proc/sys/net/ipv4/tcp_keepalive_intvl
|
||||
// 75
|
||||
Status enableTcpKeepAlives(Fd sock, unsigned idleTime, unsigned numProbes, unsigned probeInterval);
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif /* NETDUTILS_SOCKETOPTION_H */
|
||||
136
staticlibs/netd/libnetdutils/include/netdutils/Status.h
Normal file
136
staticlibs/netd/libnetdutils/include/netdutils/Status.h
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETUTILS_STATUS_H
|
||||
#define NETUTILS_STATUS_H
|
||||
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
#include <ostream>
|
||||
|
||||
#include <android-base/result.h>
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
// Simple status implementation suitable for use on the stack in low
|
||||
// or moderate performance code. This can definitely be improved but
|
||||
// for now short string optimization is expected to keep the common
|
||||
// success case fast.
|
||||
//
|
||||
// Status is implicitly movable via the default noexcept move constructor
|
||||
// and noexcept move-assignment operator.
|
||||
class [[nodiscard]] Status {
|
||||
public:
|
||||
Status() = default;
|
||||
explicit Status(int code) : mCode(code) {}
|
||||
|
||||
// Constructs an error Status, |code| must be non-zero.
|
||||
Status(int code, std::string msg) : mCode(code), mMsg(std::move(msg)) { assert(!ok()); }
|
||||
|
||||
Status(android::base::Result<void> result)
|
||||
: mCode(result.ok() ? 0 : result.error().code()),
|
||||
mMsg(result.ok() ? "" : result.error().message()) {}
|
||||
|
||||
int code() const { return mCode; }
|
||||
|
||||
bool ok() const { return code() == 0; }
|
||||
|
||||
const std::string& msg() const { return mMsg; }
|
||||
|
||||
// Explicitly ignores the Status without triggering [[nodiscard]] errors.
|
||||
void ignoreError() const {}
|
||||
|
||||
bool operator==(const Status& other) const { return code() == other.code(); }
|
||||
bool operator!=(const Status& other) const { return !(*this == other); }
|
||||
|
||||
private:
|
||||
int mCode = 0;
|
||||
std::string mMsg;
|
||||
};
|
||||
|
||||
namespace status {
|
||||
|
||||
const Status ok{0};
|
||||
// EOF is not part of errno space, we'll place it far above the
|
||||
// highest existing value.
|
||||
const Status eof{0x10001, "end of file"};
|
||||
const Status undefined{std::numeric_limits<int>::max(), "undefined"};
|
||||
|
||||
} // namespace status
|
||||
|
||||
// Return true if status is "OK". This is sometimes preferable to
|
||||
// status.ok() when we want to check the state of Status-like objects
|
||||
// that implicitly cast to Status.
|
||||
inline bool isOk(const Status& status) {
|
||||
return status.ok();
|
||||
}
|
||||
|
||||
// For use only in tests. Used for both Status and Status-like objects. See also isOk().
|
||||
#define EXPECT_OK(status) EXPECT_TRUE(isOk(status))
|
||||
#define ASSERT_OK(status) ASSERT_TRUE(isOk(status))
|
||||
|
||||
// Documents that status is expected to be ok. This function may log
|
||||
// (or assert when running in debug mode) if status has an unexpected value.
|
||||
inline void expectOk(const Status& /*status*/) {
|
||||
// TODO: put something here, for now this function serves solely as documentation.
|
||||
}
|
||||
|
||||
// Convert POSIX errno to a Status object.
|
||||
// If Status is extended to have more features, this mapping may
|
||||
// become more complex.
|
||||
Status statusFromErrno(int err, const std::string& msg);
|
||||
|
||||
// Helper that checks Status-like object (notably StatusOr) against a
|
||||
// value in the errno space.
|
||||
bool equalToErrno(const Status& status, int err);
|
||||
|
||||
// Helper that converts Status-like object (notably StatusOr) to a
|
||||
// message.
|
||||
std::string toString(const Status& status);
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Status& s);
|
||||
|
||||
// Evaluate 'stmt' to a Status object and if it results in an error, return that
|
||||
// error. Use 'tmp' as a variable name to avoid shadowing any variables named
|
||||
// tmp.
|
||||
#define RETURN_IF_NOT_OK_IMPL(tmp, stmt) \
|
||||
do { \
|
||||
::android::netdutils::Status tmp = (stmt); \
|
||||
if (!isOk(tmp)) { \
|
||||
return tmp; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
// Create a unique variable name to avoid shadowing local variables.
|
||||
#define RETURN_IF_NOT_OK_CONCAT(line, stmt) RETURN_IF_NOT_OK_IMPL(__CONCAT(_status_, line), stmt)
|
||||
|
||||
// Macro to allow exception-like handling of error return values.
|
||||
//
|
||||
// If the evaluation of stmt results in an error, return that error
|
||||
// from current function.
|
||||
//
|
||||
// Example usage:
|
||||
// Status bar() { ... }
|
||||
//
|
||||
// RETURN_IF_NOT_OK(status);
|
||||
// RETURN_IF_NOT_OK(bar());
|
||||
#define RETURN_IF_NOT_OK(stmt) RETURN_IF_NOT_OK_CONCAT(__LINE__, stmt)
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif /* NETUTILS_STATUS_H */
|
||||
119
staticlibs/netd/libnetdutils/include/netdutils/StatusOr.h
Normal file
119
staticlibs/netd/libnetdutils/include/netdutils/StatusOr.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETUTILS_STATUSOR_H
|
||||
#define NETUTILS_STATUSOR_H
|
||||
|
||||
#include <cassert>
|
||||
#include "netdutils/Status.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
// Wrapper around a combination of Status and application value type.
|
||||
// T may be any copyable or movable type.
|
||||
template <typename T>
|
||||
class [[nodiscard]] StatusOr {
|
||||
public:
|
||||
// Constructs a new StatusOr with status::undefined status.
|
||||
// This is marked 'explicit' to try to catch cases like 'return {};',
|
||||
// where people think StatusOr<std::vector<int>> will be initialized
|
||||
// with an empty vector, instead of a status::undefined.
|
||||
explicit StatusOr() = default;
|
||||
|
||||
// Implicit copy constructor and construction from T.
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
StatusOr(Status status) : mStatus(std::move(status)) { assert(!isOk(mStatus)); }
|
||||
|
||||
// Implicit construction from T. It is convenient and sensible to be able
|
||||
// to do 'return T()' when the return type is StatusOr<T>.
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
StatusOr(const T& value) : mStatus(status::ok), mValue(value) {}
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
StatusOr(T&& value) : mStatus(status::ok), mValue(std::move(value)) {}
|
||||
|
||||
// Move constructor ok (if T supports move)
|
||||
StatusOr(StatusOr&&) noexcept = default;
|
||||
// Move assignment ok (if T supports move)
|
||||
StatusOr& operator=(StatusOr&&) noexcept = default;
|
||||
// Copy constructor ok (if T supports copy)
|
||||
StatusOr(const StatusOr&) = default;
|
||||
// Copy assignment ok (if T supports copy)
|
||||
StatusOr& operator=(const StatusOr&) = default;
|
||||
|
||||
// Returns a const reference to wrapped type.
|
||||
// It is an error to call value() when !isOk(status())
|
||||
const T& value() const & { return mValue; }
|
||||
const T&& value() const && { return mValue; }
|
||||
|
||||
// Returns an rvalue reference to wrapped type
|
||||
// It is an error to call value() when !isOk(status())
|
||||
//
|
||||
// If T is expensive to copy but supports efficient move, it can be moved
|
||||
// out of a StatusOr as follows:
|
||||
// T value = std::move(statusor).value();
|
||||
T& value() & { return mValue; }
|
||||
T&& value() && { return mValue; }
|
||||
|
||||
// Returns the Status object assigned at construction time.
|
||||
const Status status() const { return mStatus; }
|
||||
|
||||
// Explicitly ignores the Status without triggering [[nodiscard]] errors.
|
||||
void ignoreError() const {}
|
||||
|
||||
// Implicit cast to Status.
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
operator Status() const { return status(); }
|
||||
|
||||
private:
|
||||
Status mStatus = status::undefined;
|
||||
T mValue;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline std::ostream& operator<<(std::ostream& os, const StatusOr<T>& s) {
|
||||
return os << "StatusOr[status: " << s.status() << "]";
|
||||
}
|
||||
|
||||
#define ASSIGN_OR_RETURN_IMPL(tmp, lhs, stmt) \
|
||||
auto tmp = (stmt); \
|
||||
RETURN_IF_NOT_OK(tmp); \
|
||||
lhs = std::move(tmp.value());
|
||||
|
||||
#define ASSIGN_OR_RETURN_CONCAT(line, lhs, stmt) \
|
||||
ASSIGN_OR_RETURN_IMPL(__CONCAT(_status_or_, line), lhs, stmt)
|
||||
|
||||
// Macro to allow exception-like handling of error return values.
|
||||
//
|
||||
// If the evaluation of stmt results in an error, return that error
|
||||
// from the current function. Otherwise, assign the result to lhs.
|
||||
//
|
||||
// This macro supports both move and copy assignment operators. lhs
|
||||
// may be either a new local variable or an existing non-const
|
||||
// variable accessible in the current scope.
|
||||
//
|
||||
// Example usage:
|
||||
// StatusOr<MyType> foo() { ... }
|
||||
//
|
||||
// ASSIGN_OR_RETURN(auto myVar, foo());
|
||||
// ASSIGN_OR_RETURN(myExistingVar, foo());
|
||||
// ASSIGN_OR_RETURN(myMemberVar, foo());
|
||||
#define ASSIGN_OR_RETURN(lhs, stmt) ASSIGN_OR_RETURN_CONCAT(__LINE__, lhs, stmt)
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif /* NETUTILS_STATUSOR_H */
|
||||
53
staticlibs/netd/libnetdutils/include/netdutils/Stopwatch.h
Normal file
53
staticlibs/netd/libnetdutils/include/netdutils/Stopwatch.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETDUTILS_STOPWATCH_H
|
||||
#define NETDUTILS_STOPWATCH_H
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
class Stopwatch {
|
||||
private:
|
||||
using clock = std::chrono::steady_clock;
|
||||
using time_point = std::chrono::time_point<clock>;
|
||||
|
||||
public:
|
||||
Stopwatch() : mStart(clock::now()) {}
|
||||
virtual ~Stopwatch() = default;
|
||||
|
||||
int64_t timeTakenUs() const { return getElapsedUs(clock::now()); }
|
||||
int64_t getTimeAndResetUs() {
|
||||
const auto& now = clock::now();
|
||||
int64_t elapsed = getElapsedUs(now);
|
||||
mStart = now;
|
||||
return elapsed;
|
||||
}
|
||||
|
||||
private:
|
||||
time_point mStart;
|
||||
|
||||
int64_t getElapsedUs(const time_point& now) const {
|
||||
return (std::chrono::duration_cast<std::chrono::microseconds>(now - mStart)).count();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif // NETDUTILS_STOPWATCH_H
|
||||
204
staticlibs/netd/libnetdutils/include/netdutils/Syscalls.h
Normal file
204
staticlibs/netd/libnetdutils/include/netdutils/Syscalls.h
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETDUTILS_SYSCALLS_H
|
||||
#define NETDUTILS_SYSCALLS_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <poll.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "netdutils/Fd.h"
|
||||
#include "netdutils/Slice.h"
|
||||
#include "netdutils/Socket.h"
|
||||
#include "netdutils/Status.h"
|
||||
#include "netdutils/StatusOr.h"
|
||||
#include "netdutils/UniqueFd.h"
|
||||
#include "netdutils/UniqueFile.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
class Syscalls {
|
||||
public:
|
||||
virtual ~Syscalls() = default;
|
||||
|
||||
virtual StatusOr<UniqueFd> open(const std::string& pathname, int flags,
|
||||
mode_t mode = 0) const = 0;
|
||||
|
||||
virtual StatusOr<UniqueFd> socket(int domain, int type, int protocol) const = 0;
|
||||
|
||||
virtual Status getsockname(Fd sock, sockaddr* addr, socklen_t* addrlen) const = 0;
|
||||
|
||||
virtual Status getsockopt(Fd sock, int level, int optname, void *optval,
|
||||
socklen_t *optlen) const = 0;
|
||||
|
||||
virtual Status setsockopt(Fd sock, int level, int optname, const void* optval,
|
||||
socklen_t optlen) const = 0;
|
||||
|
||||
virtual Status bind(Fd sock, const sockaddr* addr, socklen_t addrlen) const = 0;
|
||||
|
||||
virtual Status connect(Fd sock, const sockaddr* addr, socklen_t addrlen) const = 0;
|
||||
|
||||
virtual StatusOr<ifreq> ioctl(Fd sock, unsigned long request, ifreq* ifr) const = 0;
|
||||
|
||||
virtual StatusOr<UniqueFd> eventfd(unsigned int initval, int flags) const = 0;
|
||||
|
||||
virtual StatusOr<int> ppoll(pollfd* fds, nfds_t nfds, double timeout) const = 0;
|
||||
|
||||
virtual StatusOr<size_t> writev(Fd fd, const std::vector<iovec>& iov) const = 0;
|
||||
|
||||
virtual StatusOr<size_t> write(Fd fd, const Slice buf) const = 0;
|
||||
|
||||
virtual StatusOr<Slice> read(Fd fd, const Slice buf) const = 0;
|
||||
|
||||
virtual StatusOr<size_t> sendto(Fd sock, const Slice buf, int flags, const sockaddr* dst,
|
||||
socklen_t dstlen) const = 0;
|
||||
|
||||
virtual StatusOr<Slice> recvfrom(Fd sock, const Slice dst, int flags, sockaddr* src,
|
||||
socklen_t* srclen) const = 0;
|
||||
|
||||
virtual Status shutdown(Fd fd, int how) const = 0;
|
||||
|
||||
virtual Status close(Fd fd) const = 0;
|
||||
|
||||
virtual StatusOr<UniqueFile> fopen(const std::string& path, const std::string& mode) const = 0;
|
||||
|
||||
virtual StatusOr<int> vfprintf(FILE* file, const char* format, va_list ap) const = 0;
|
||||
|
||||
virtual StatusOr<int> vfscanf(FILE* file, const char* format, va_list ap) const = 0;
|
||||
|
||||
virtual Status fclose(FILE* file) const = 0;
|
||||
|
||||
virtual StatusOr<pid_t> fork() const = 0;
|
||||
|
||||
// va_args helpers
|
||||
// va_start doesn't work when the preceding argument is a reference
|
||||
// type so we're forced to use const char*.
|
||||
StatusOr<int> fprintf(FILE* file, const char* format, ...) const {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
auto result = vfprintf(file, format, ap);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
// va_start doesn't work when the preceding argument is a reference
|
||||
// type so we're forced to use const char*.
|
||||
StatusOr<int> fscanf(FILE* file, const char* format, ...) const {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
auto result = vfscanf(file, format, ap);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Templated helpers that forward directly to methods declared above
|
||||
template <typename SockaddrT>
|
||||
StatusOr<SockaddrT> getsockname(Fd sock) const {
|
||||
SockaddrT addr = {};
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
RETURN_IF_NOT_OK(getsockname(sock, asSockaddrPtr(&addr), &addrlen));
|
||||
return addr;
|
||||
}
|
||||
|
||||
template <typename SockoptT>
|
||||
Status getsockopt(Fd sock, int level, int optname, void* optval, socklen_t* optlen) const {
|
||||
return getsockopt(sock, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
template <typename SockoptT>
|
||||
Status setsockopt(Fd sock, int level, int optname, const SockoptT& opt) const {
|
||||
return setsockopt(sock, level, optname, &opt, sizeof(opt));
|
||||
}
|
||||
|
||||
template <typename SockaddrT>
|
||||
Status bind(Fd sock, const SockaddrT& addr) const {
|
||||
return bind(sock, asSockaddrPtr(&addr), sizeof(addr));
|
||||
}
|
||||
|
||||
template <typename SockaddrT>
|
||||
Status connect(Fd sock, const SockaddrT& addr) const {
|
||||
return connect(sock, asSockaddrPtr(&addr), sizeof(addr));
|
||||
}
|
||||
|
||||
template <size_t size>
|
||||
StatusOr<std::array<uint16_t, size>> ppoll(const std::array<Fd, size>& fds, uint16_t events,
|
||||
double timeout) const {
|
||||
std::array<pollfd, size> tmp;
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
tmp[i].fd = fds[i].get();
|
||||
tmp[i].events = events;
|
||||
tmp[i].revents = 0;
|
||||
}
|
||||
RETURN_IF_NOT_OK(ppoll(tmp.data(), tmp.size(), timeout).status());
|
||||
std::array<uint16_t, size> out;
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
out[i] = tmp[i].revents;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename SockaddrT>
|
||||
StatusOr<size_t> sendto(Fd sock, const Slice buf, int flags, const SockaddrT& dst) const {
|
||||
return sendto(sock, buf, flags, asSockaddrPtr(&dst), sizeof(dst));
|
||||
}
|
||||
|
||||
// Ignore src sockaddr
|
||||
StatusOr<Slice> recvfrom(Fd sock, const Slice dst, int flags) const {
|
||||
return recvfrom(sock, dst, flags, nullptr, nullptr);
|
||||
}
|
||||
|
||||
template <typename SockaddrT>
|
||||
StatusOr<std::pair<Slice, SockaddrT>> recvfrom(Fd sock, const Slice dst, int flags) const {
|
||||
SockaddrT addr = {};
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
ASSIGN_OR_RETURN(auto used, recvfrom(sock, dst, flags, asSockaddrPtr(&addr), &addrlen));
|
||||
return std::make_pair(used, addr);
|
||||
}
|
||||
};
|
||||
|
||||
// Specialized singleton that supports zero initialization and runtime
|
||||
// override of contained pointer.
|
||||
class SyscallsHolder {
|
||||
public:
|
||||
~SyscallsHolder();
|
||||
|
||||
// Return a pointer to an unowned instance of Syscalls.
|
||||
Syscalls& get();
|
||||
|
||||
// Testing only: set the value returned by getSyscalls. Return the old value.
|
||||
// Callers are responsible for restoring the previous value returned
|
||||
// by getSyscalls to avoid leaks.
|
||||
Syscalls& swap(Syscalls& syscalls);
|
||||
|
||||
private:
|
||||
std::atomic<Syscalls*> mSyscalls{nullptr};
|
||||
};
|
||||
|
||||
// Syscalls instance used throughout netdutils
|
||||
extern SyscallsHolder sSyscalls;
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif /* NETDUTILS_SYSCALLS_H */
|
||||
83
staticlibs/netd/libnetdutils/include/netdutils/ThreadUtil.h
Normal file
83
staticlibs/netd/libnetdutils/include/netdutils/ThreadUtil.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETDUTILS_THREADUTIL_H
|
||||
#define NETDUTILS_THREADUTIL_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include <memory>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
struct scoped_pthread_attr {
|
||||
scoped_pthread_attr() { pthread_attr_init(&attr); }
|
||||
~scoped_pthread_attr() { pthread_attr_destroy(&attr); }
|
||||
|
||||
int detach() { return -pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); }
|
||||
|
||||
pthread_attr_t attr;
|
||||
};
|
||||
|
||||
inline void setThreadName(std::string name) {
|
||||
// MAX_TASK_COMM_LEN=16 is not exported by bionic.
|
||||
const size_t MAX_TASK_COMM_LEN = 16;
|
||||
|
||||
// Crop name to 16 bytes including the NUL byte, as required by pthread_setname_np()
|
||||
if (name.size() >= MAX_TASK_COMM_LEN) name.resize(MAX_TASK_COMM_LEN - 1);
|
||||
|
||||
if (int ret = pthread_setname_np(pthread_self(), name.c_str()); ret != 0) {
|
||||
LOG(WARNING) << "Unable to set thread name to " << name << ": " << strerror(ret);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void* runAndDelete(void* obj) {
|
||||
std::unique_ptr<T> handler(reinterpret_cast<T*>(obj));
|
||||
setThreadName(handler->threadName().c_str());
|
||||
handler->run();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline int threadLaunch(T* obj) {
|
||||
if (obj == nullptr) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
scoped_pthread_attr scoped_attr;
|
||||
|
||||
int rval = scoped_attr.detach();
|
||||
if (rval != 0) {
|
||||
return rval;
|
||||
}
|
||||
|
||||
pthread_t thread;
|
||||
rval = pthread_create(&thread, &scoped_attr.attr, &runAndDelete<T>, obj);
|
||||
if (rval != 0) {
|
||||
LOG(WARNING) << __func__ << ": pthread_create failed: " << rval;
|
||||
return -rval;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif // NETDUTILS_THREADUTIL_H
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETDUTILS_UID_CONSTANTS_H
|
||||
#define NETDUTILS_UID_CONSTANTS_H
|
||||
|
||||
// These are used by both eBPF kernel programs and netd, we cannot put them in NetdConstant.h since
|
||||
// we have to minimize the number of headers included by the BPF kernel program.
|
||||
#define MIN_SYSTEM_UID 0
|
||||
#define MAX_SYSTEM_UID 9999
|
||||
|
||||
#define PER_USER_RANGE 100000
|
||||
|
||||
#endif // NETDUTILS_UID_CONSTANTS_H
|
||||
71
staticlibs/netd/libnetdutils/include/netdutils/UniqueFd.h
Normal file
71
staticlibs/netd/libnetdutils/include/netdutils/UniqueFd.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETUTILS_UNIQUEFD_H
|
||||
#define NETUTILS_UNIQUEFD_H
|
||||
|
||||
#include <unistd.h>
|
||||
#include <ostream>
|
||||
|
||||
#include "netdutils/Fd.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
// Stricter unique_fd implementation that:
|
||||
// *) Does not implement release()
|
||||
// *) Does not implicitly cast to int
|
||||
// *) Uses a strongly typed wrapper (Fd) for the underlying file descriptor
|
||||
//
|
||||
// Users of UniqueFd should endeavor to treat this as a completely
|
||||
// opaque object. The only code that should interpret the wrapped
|
||||
// value is in Syscalls.h
|
||||
class UniqueFd {
|
||||
public:
|
||||
UniqueFd() = default;
|
||||
|
||||
UniqueFd(Fd fd) : mFd(fd) {}
|
||||
|
||||
~UniqueFd() { reset(); }
|
||||
|
||||
// Disallow copy
|
||||
UniqueFd(const UniqueFd&) = delete;
|
||||
UniqueFd& operator=(const UniqueFd&) = delete;
|
||||
|
||||
// Allow move
|
||||
UniqueFd(UniqueFd&& other) { std::swap(mFd, other.mFd); }
|
||||
UniqueFd& operator=(UniqueFd&& other) {
|
||||
std::swap(mFd, other.mFd);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Cleanup any currently owned Fd, replacing it with the optional
|
||||
// parameter fd
|
||||
void reset(Fd fd = Fd());
|
||||
|
||||
// Implict cast to Fd
|
||||
operator const Fd &() const { return mFd; }
|
||||
|
||||
private:
|
||||
Fd mFd;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const UniqueFd& fd);
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif /* NETUTILS_UNIQUEFD_H */
|
||||
35
staticlibs/netd/libnetdutils/include/netdutils/UniqueFile.h
Normal file
35
staticlibs/netd/libnetdutils/include/netdutils/UniqueFile.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 NETDUTILS_UNIQUEFILE_H
|
||||
#define NETDUTILS_UNIQUEFILE_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <memory>
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
struct UniqueFileDtor {
|
||||
void operator()(FILE* file) const;
|
||||
};
|
||||
|
||||
using UniqueFile = std::unique_ptr<FILE, UniqueFileDtor>;
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif /* NETDUTILS_UNIQUEFILE_H */
|
||||
Reference in New Issue
Block a user