/* * 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 <sys/uio.h> #include "netdutils/Slice.h" #include "netdutils/Socket.h" #include "netdutils/Status.h" #include "netdutils/StatusOr.h" #include "netdutils/UniqueFd.h" #include "netdutils/UniqueFile.h" namespace android { namespace netdutils { class Syscalls { public: virtual ~Syscalls() = default; virtual StatusOr<UniqueFd> open(const std::string& pathname, int flags, mode_t mode = 0) const = 0; virtual StatusOr<UniqueFd> socket(int domain, int type, int protocol) const = 0; virtual Status getsockname(Fd sock, sockaddr* addr, socklen_t* addrlen) const = 0; virtual Status getsockopt(Fd sock, int level, int optname, void *optval, socklen_t *optlen) const = 0; virtual Status setsockopt(Fd sock, int level, int optname, const void* optval, socklen_t optlen) const = 0; virtual Status bind(Fd sock, const sockaddr* addr, socklen_t addrlen) const = 0; virtual Status connect(Fd sock, const sockaddr* addr, socklen_t addrlen) const = 0; virtual StatusOr<UniqueFd> eventfd(unsigned int initval, int flags) const = 0; virtual StatusOr<int> ppoll(pollfd* fds, nfds_t nfds, double timeout) const = 0; virtual StatusOr<size_t> writev(Fd fd, const std::vector<iovec>& iov) const = 0; virtual StatusOr<size_t> write(Fd fd, const Slice buf) const = 0; virtual StatusOr<Slice> read(Fd fd, const Slice buf) const = 0; virtual StatusOr<size_t> sendto(Fd sock, const Slice buf, int flags, const sockaddr* dst, socklen_t dstlen) const = 0; virtual StatusOr<Slice> recvfrom(Fd sock, const Slice dst, int flags, sockaddr* src, socklen_t* srclen) const = 0; virtual Status shutdown(Fd fd, int how) const = 0; virtual Status close(Fd fd) const = 0; virtual StatusOr<UniqueFile> fopen(const std::string& path, const std::string& mode) const = 0; virtual StatusOr<int> vfprintf(FILE* file, const char* format, va_list ap) const = 0; virtual StatusOr<int> vfscanf(FILE* file, const char* format, va_list ap) const = 0; virtual Status fclose(FILE* file) const = 0; virtual StatusOr<pid_t> fork() const = 0; // va_args helpers // va_start doesn't work when the preceding argument is a reference // type so we're forced to use const char*. StatusOr<int> fprintf(FILE* file, const char* format, ...) const { va_list ap; va_start(ap, format); auto result = vfprintf(file, format, ap); va_end(ap); return result; } // va_start doesn't work when the preceding argument is a reference // type so we're forced to use const char*. StatusOr<int> fscanf(FILE* file, const char* format, ...) const { va_list ap; va_start(ap, format); auto result = vfscanf(file, format, ap); va_end(ap); return result; } // Templated helpers that forward directly to methods declared above template <typename SockaddrT> StatusOr<SockaddrT> getsockname(Fd sock) const { SockaddrT addr = {}; socklen_t addrlen = sizeof(addr); RETURN_IF_NOT_OK(getsockname(sock, asSockaddrPtr(&addr), &addrlen)); return addr; } template <typename SockoptT> Status getsockopt(Fd sock, int level, int optname, void* optval, socklen_t* optlen) const { return getsockopt(sock, level, optname, optval, optlen); } template <typename SockoptT> Status setsockopt(Fd sock, int level, int optname, const SockoptT& opt) const { return setsockopt(sock, level, optname, &opt, sizeof(opt)); } template <typename SockaddrT> Status bind(Fd sock, const SockaddrT& addr) const { return bind(sock, asSockaddrPtr(&addr), sizeof(addr)); } template <typename SockaddrT> Status connect(Fd sock, const SockaddrT& addr) const { return connect(sock, asSockaddrPtr(&addr), sizeof(addr)); } template <size_t size> StatusOr<std::array<uint16_t, size>> ppoll(const std::array<Fd, size>& fds, uint16_t events, double timeout) const { std::array<pollfd, size> tmp; for (size_t i = 0; i < size; ++i) { tmp[i].fd = fds[i].get(); tmp[i].events = events; tmp[i].revents = 0; } RETURN_IF_NOT_OK(ppoll(tmp.data(), tmp.size(), timeout).status()); std::array<uint16_t, size> out; for (size_t i = 0; i < size; ++i) { out[i] = tmp[i].revents; } return out; } template <typename SockaddrT> StatusOr<size_t> sendto(Fd sock, const Slice buf, int flags, const SockaddrT& dst) const { return sendto(sock, buf, flags, asSockaddrPtr(&dst), sizeof(dst)); } // Ignore src sockaddr StatusOr<Slice> recvfrom(Fd sock, const Slice dst, int flags) const { return recvfrom(sock, dst, flags, nullptr, nullptr); } template <typename SockaddrT> StatusOr<std::pair<Slice, SockaddrT>> recvfrom(Fd sock, const Slice dst, int flags) const { SockaddrT addr = {}; socklen_t addrlen = sizeof(addr); ASSIGN_OR_RETURN(auto used, recvfrom(sock, dst, flags, asSockaddrPtr(&addr), &addrlen)); return std::make_pair(used, addr); } }; // Specialized singleton that supports zero initialization and runtime // override of contained pointer. class SyscallsHolder { public: ~SyscallsHolder(); // Return a pointer to an unowned instance of Syscalls. Syscalls& get(); // Testing only: set the value returned by getSyscalls. Return the old value. // Callers are responsible for restoring the previous value returned // by getSyscalls to avoid leaks. Syscalls& swap(Syscalls& syscalls); private: std::atomic<Syscalls*> mSyscalls{nullptr}; }; // Syscalls instance used throughout netdutils extern SyscallsHolder sSyscalls; } // namespace netdutils } // namespace android #endif /* NETDUTILS_SYSCALLS_H */