Add utility classes (Slice, Fd, Status, etc)
Test: as follows
- built
- flashed
- bootedt log
- netdutils_test passes
- unsubmitted NFLogListenerTest passes
Bug: 28806131
Change-Id: I17846a0dee1edca55df10e5464e607109d978cb5
diff --git a/libnetdutils/include/netdutils/Fd.h b/libnetdutils/include/netdutils/Fd.h
new file mode 100644
index 0000000..7db4087
--- /dev/null
+++ b/libnetdutils/include/netdutils/Fd.h
@@ -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 */
diff --git a/libnetdutils/include/netdutils/Handle.h b/libnetdutils/include/netdutils/Handle.h
new file mode 100644
index 0000000..82083d4
--- /dev/null
+++ b/libnetdutils/include/netdutils/Handle.h
@@ -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 */
diff --git a/libnetdutils/include/netdutils/Math.h b/libnetdutils/include/netdutils/Math.h
new file mode 100644
index 0000000..c41fbf5
--- /dev/null
+++ b/libnetdutils/include/netdutils/Math.h
@@ -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 */
diff --git a/libnetdutils/include/netdutils/Misc.h b/libnetdutils/include/netdutils/Misc.h
new file mode 100644
index 0000000..41f5778
--- /dev/null
+++ b/libnetdutils/include/netdutils/Misc.h
@@ -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 */
diff --git a/libnetdutils/include/netdutils/MockSyscalls.h b/libnetdutils/include/netdutils/MockSyscalls.h
new file mode 100644
index 0000000..701d4d5
--- /dev/null
+++ b/libnetdutils/include/netdutils/MockSyscalls.h
@@ -0,0 +1,76 @@
+/*
+ * 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(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));
+};
+
+// 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 */
diff --git a/libnetdutils/include/netdutils/Netfilter.h b/libnetdutils/include/netdutils/Netfilter.h
new file mode 100644
index 0000000..22736f1
--- /dev/null
+++ b/libnetdutils/include/netdutils/Netfilter.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 */
diff --git a/libnetdutils/include/netdutils/Netlink.h b/libnetdutils/include/netdutils/Netlink.h
new file mode 100644
index 0000000..ee5183a
--- /dev/null
+++ b/libnetdutils/include/netdutils/Netlink.h
@@ -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 */
diff --git a/libnetdutils/include/netdutils/Slice.h b/libnetdutils/include/netdutils/Slice.h
new file mode 100644
index 0000000..40f173e
--- /dev/null
+++ b/libnetdutils/include/netdutils/Slice.h
@@ -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.
+ */
+
+#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 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 */
diff --git a/libnetdutils/include/netdutils/Socket.h b/libnetdutils/include/netdutils/Socket.h
new file mode 100644
index 0000000..0bb5682
--- /dev/null
+++ b/libnetdutils/include/netdutils/Socket.h
@@ -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 <sys/socket.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);
+}
+
+} // namespace netdutils
+} // namespace android
diff --git a/libnetdutils/include/netdutils/Status.h b/libnetdutils/include/netdutils/Status.h
new file mode 100644
index 0000000..eacf791
--- /dev/null
+++ b/libnetdutils/include/netdutils/Status.h
@@ -0,0 +1,108 @@
+/*
+ * 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()) && (msg() == other.msg());
+ }
+ bool operator!=(const Status& other) const { return !(*this == other); }
+
+ private:
+ int mCode = 0;
+ std::string mMsg;
+};
+
+namespace status {
+
+const Status ok{0};
+const Status eof{256, "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.
+//
+// TODO: msg is only a placeholder for now
+Status statusFromErrno(int err, const std::string& msg);
+
+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 */
diff --git a/libnetdutils/include/netdutils/StatusOr.h b/libnetdutils/include/netdutils/StatusOr.h
new file mode 100644
index 0000000..6afbfcb
--- /dev/null
+++ b/libnetdutils/include/netdutils/StatusOr.h
@@ -0,0 +1,103 @@
+/*
+ * 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) {
+ os << "StatusOr[status: " << s.status();
+ if (isOk(s)) {
+ os << ", value: " << s.value();
+ }
+ return os << "]";
+}
+
+#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 */
diff --git a/libnetdutils/include/netdutils/Syscalls.h b/libnetdutils/include/netdutils/Syscalls.h
new file mode 100644
index 0000000..5d8ce68
--- /dev/null
+++ b/libnetdutils/include/netdutils/Syscalls.h
@@ -0,0 +1,151 @@
+/*
+ * 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_SYSCALLS_H
+#define NETUTILS_SYSCALLS_H
+
+#include <poll.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"
+
+namespace android {
+namespace netdutils {
+
+class Syscalls {
+ public:
+ virtual ~Syscalls() = default;
+
+ 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;
+
+ // 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 /* NETUTILS_SYSCALLS_H */
diff --git a/libnetdutils/include/netdutils/UniqueFd.h b/libnetdutils/include/netdutils/UniqueFd.h
new file mode 100644
index 0000000..3b63f34
--- /dev/null
+++ b/libnetdutils/include/netdutils/UniqueFd.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 */