upload android base code part6
This commit is contained in:
parent
421e214c7d
commit
4e516ec6ed
35396 changed files with 9188716 additions and 0 deletions
30
android/system/netd/libnetdutils/Android.bp
Normal file
30
android/system/netd/libnetdutils/Android.bp
Normal file
|
@ -0,0 +1,30 @@
|
|||
cc_library_shared {
|
||||
name: "libnetdutils",
|
||||
srcs: [
|
||||
"Fd.cpp",
|
||||
"Netfilter.cpp",
|
||||
"Netlink.cpp",
|
||||
"Slice.cpp",
|
||||
"Socket.cpp",
|
||||
"Status.cpp",
|
||||
"Syscalls.cpp",
|
||||
"UniqueFd.cpp",
|
||||
"UniqueFile.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
],
|
||||
export_include_dirs: ["include"],
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "netdutils_test",
|
||||
srcs: [
|
||||
"SliceTest.cpp",
|
||||
"StatusTest.cpp",
|
||||
"FdTest.cpp",
|
||||
"SyscallsTest.cpp",
|
||||
],
|
||||
static_libs: ["libgmock"],
|
||||
shared_libs: ["libnetdutils"],
|
||||
}
|
27
android/system/netd/libnetdutils/Fd.cpp
Normal file
27
android/system/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
|
144
android/system/netd/libnetdutils/FdTest.cpp
Normal file
144
android/system/netd/libnetdutils/FdTest.cpp
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* 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 = fd1;
|
||||
const Fd fd4(8);
|
||||
const Fd fd5(fd4);
|
||||
const Fd fd6 = fd4;
|
||||
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));
|
||||
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);
|
||||
EXPECT_FALSE(isWellFormed(u1));
|
||||
EXPECT_TRUE(isWellFormed(u2));
|
||||
UniqueFd u3;
|
||||
u3 = std::move(u2);
|
||||
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
|
30
android/system/netd/libnetdutils/Netfilter.cpp
Normal file
30
android/system/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 <endian.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" << be16toh(msg.res_id) << "]"
|
||||
<< std::dec;
|
||||
}
|
78
android/system/netd/libnetdutils/Netlink.cpp
Normal file
78
android/system/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
android/system/netd/libnetdutils/Slice.cpp
Normal file
61
android/system/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
|
80
android/system/netd/libnetdutils/SliceTest.cpp
Normal file
80
android/system/netd/libnetdutils/SliceTest.cpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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);
|
||||
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());
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
35
android/system/netd/libnetdutils/Socket.cpp
Normal file
35
android/system/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
|
47
android/system/netd/libnetdutils/Status.cpp
Normal file
47
android/system/netd/libnetdutils/Status.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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/Status.h"
|
||||
#include "android-base/stringprintf.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
void expectOk(const Status&) {
|
||||
// TODO: put something here, for now this function serves solely as documentation.
|
||||
}
|
||||
|
||||
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
|
56
android/system/netd/libnetdutils/StatusTest.cpp
Normal file
56
android/system/netd/libnetdutils/StatusTest.cpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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/Status.h"
|
||||
#include "netdutils/StatusOr.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
TEST(StatusTest, smoke) {
|
||||
// Expect the following lines to compile
|
||||
Status status1(1);
|
||||
Status status2(status1);
|
||||
Status status3 = status1;
|
||||
const Status status4(8);
|
||||
const Status status5(status4);
|
||||
const Status status6 = status4;
|
||||
|
||||
// Default constructor
|
||||
EXPECT_EQ(status::ok, Status());
|
||||
}
|
||||
|
||||
TEST(StatusOrTest, ostream) {
|
||||
{
|
||||
StatusOr<int> so(11);
|
||||
std::stringstream ss;
|
||||
ss << so;
|
||||
EXPECT_EQ("StatusOr[status: Status[code: 0, msg: ], value: 11]", ss.str());
|
||||
}
|
||||
{
|
||||
StatusOr<int> err(status::undefined);
|
||||
std::stringstream ss;
|
||||
ss << err;
|
||||
EXPECT_EQ("StatusOr[status: Status[code: 2147483647, msg: undefined]]", ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
240
android/system/netd/libnetdutils/Syscalls.cpp
Normal file
240
android/system/netd/libnetdutils/Syscalls.cpp
Normal file
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* 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 <atomic>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "netdutils/Syscalls.h"
|
||||
|
||||
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 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<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> 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 == NULL) {
|
||||
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
|
182
android/system/netd/libnetdutils/SyscallsTest.cpp
Normal file
182
android/system/netd/libnetdutils/SyscallsTest.cpp
Normal file
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* 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::ByMove;
|
||||
using testing::DoAll;
|
||||
using testing::Invoke;
|
||||
using testing::Mock;
|
||||
using testing::Return;
|
||||
using testing::StrictMock;
|
||||
using testing::_;
|
||||
|
||||
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))));
|
||||
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, 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) {
|
||||
memcpy(src, &expected, sizeof(src));
|
||||
*srclen = sizeof(expected);
|
||||
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
|
38
android/system/netd/libnetdutils/UniqueFd.cpp
Normal file
38
android/system/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
android/system/netd/libnetdutils/UniqueFile.cpp
Normal file
31
android/system/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 auto& sys = sSyscalls.get();
|
||||
sys.fclose(file);
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
54
android/system/netd/libnetdutils/include/netdutils/Fd.h
Normal file
54
android/system/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
android/system/netd/libnetdutils/include/netdutils/Handle.h
Normal file
74
android/system/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 */
|
40
android/system/netd/libnetdutils/include/netdutils/Math.h
Normal file
40
android/system/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 */
|
62
android/system/netd/libnetdutils/include/netdutils/Misc.h
Normal file
62
android/system/netd/libnetdutils/include/netdutils/Misc.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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;
|
||||
Cleanup(FnT fn) : mFn(fn) {}
|
||||
~Cleanup() { mFn(); }
|
||||
|
||||
void release() { mFn = {}; }
|
||||
|
||||
private:
|
||||
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,85 @@
|
|||
/*
|
||||
* 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(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));
|
||||
|
||||
// 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(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 */
|
|
@ -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
android/system/netd/libnetdutils/include/netdutils/Netlink.h
Normal file
55
android/system/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 */
|
153
android/system/netd/libnetdutils/include/netdutils/Slice.h
Normal file
153
android/system/netd/libnetdutils/include/netdutils/Slice.h
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* 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);
|
||||
|
||||
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);
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif /* NETUTILS_SLICE_H */
|
44
android/system/netd/libnetdutils/include/netdutils/Socket.h
Normal file
44
android/system/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 */
|
114
android/system/netd/libnetdutils/include/netdutils/Status.h
Normal file
114
android/system/netd/libnetdutils/include/netdutils/Status.h
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* 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 <ostream>
|
||||
|
||||
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.
|
||||
class Status {
|
||||
public:
|
||||
Status() = default;
|
||||
|
||||
Status(int code) : mCode(code) {}
|
||||
|
||||
Status(int code, const std::string& msg) : mCode(code), mMsg(msg) { assert(!ok()); }
|
||||
|
||||
int code() const { return mCode; }
|
||||
|
||||
bool ok() const { return code() == 0; }
|
||||
|
||||
const std::string& msg() const { return mMsg; }
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
// Document that status is expected to be ok. This function may log
|
||||
// (or assert when running in debug mode) if status has an unexpected
|
||||
// value.
|
||||
void expectOk(const Status& status);
|
||||
|
||||
// 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);
|
||||
|
||||
#define RETURN_IF_NOT_OK_IMPL(tmp, stmt) \
|
||||
do { \
|
||||
::android::netdutils::Status tmp = (stmt); \
|
||||
if (!isOk(tmp)) { \
|
||||
return tmp; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#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 */
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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 StatusOr {
|
||||
public:
|
||||
StatusOr() = default;
|
||||
StatusOr(const Status status) : mStatus(status) { assert(!isOk(status)); }
|
||||
StatusOr(const T& value) : mStatus(status::ok), mValue(value) {}
|
||||
StatusOr(T&& value) : mStatus(status::ok), mValue(std::move(value)) {}
|
||||
|
||||
// Move constructor ok (if T supports move)
|
||||
StatusOr(StatusOr&&) = default;
|
||||
// Move assignment ok (if T supports move)
|
||||
StatusOr& operator=(StatusOr&&) = default;
|
||||
// Copy constructor ok (if T supports copy)
|
||||
StatusOr(const StatusOr&) = default;
|
||||
// Copy assignment ok (if T supports copy)
|
||||
StatusOr& operator=(const StatusOr&) = default;
|
||||
|
||||
// Return const references 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; }
|
||||
|
||||
// Return rvalue references to wrapped type
|
||||
// It is an error to call value() when !isOk(status())
|
||||
T& value() & { return mValue; }
|
||||
T&& value() && { return mValue; }
|
||||
|
||||
// Return status assigned in constructor
|
||||
const Status status() const { return mStatus; }
|
||||
|
||||
// Implict cast to Status
|
||||
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 */
|
189
android/system/netd/libnetdutils/include/netdutils/Syscalls.h
Normal file
189
android/system/netd/libnetdutils/include/netdutils/Syscalls.h
Normal file
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* 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 <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.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 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<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> 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 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 */
|
|
@ -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
|
||||
const operator Fd() const { return mFd; }
|
||||
|
||||
private:
|
||||
Fd mFd;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const UniqueFd& fd);
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif /* NETUTILS_UNIQUEFD_H */
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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>
|
||||
|
||||
#include "netdutils/Fd.h"
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
struct UniqueFileDtor {
|
||||
void operator()(FILE* file);
|
||||
};
|
||||
|
||||
using UniqueFile = std::unique_ptr<FILE, UniqueFileDtor>;
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif /* NETDUTILS_UNIQUEFILE_H */
|
Loading…
Add table
Add a link
Reference in a new issue