|  | // Copyright (c) 2019 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef QUICHE_QUIC_QBONE_PLATFORM_KERNEL_INTERFACE_H_ | 
|  | #define QUICHE_QUIC_QBONE_PLATFORM_KERNEL_INTERFACE_H_ | 
|  |  | 
|  | #include <errno.h> | 
|  | #include <fcntl.h> | 
|  | #include <sys/ioctl.h> | 
|  | #include <sys/socket.h> | 
|  | #include <sys/types.h> | 
|  | #include <unistd.h> | 
|  | #include <type_traits> | 
|  | #include <utility> | 
|  |  | 
|  | namespace quic { | 
|  |  | 
|  | // A wrapper for making syscalls to the kernel, so that syscalls can be | 
|  | // mocked during testing. | 
|  | class KernelInterface { | 
|  | public: | 
|  | virtual ~KernelInterface() {} | 
|  | virtual int bind(int fd, const struct sockaddr* addr, socklen_t addr_len) = 0; | 
|  | virtual int close(int fd) = 0; | 
|  | virtual int ioctl(int fd, int request, void* argp) = 0; | 
|  | virtual int open(const char* pathname, int flags) = 0; | 
|  | virtual ssize_t read(int fd, void* buf, size_t count) = 0; | 
|  | virtual ssize_t recvfrom(int sockfd, | 
|  | void* buf, | 
|  | size_t len, | 
|  | int flags, | 
|  | struct sockaddr* src_addr, | 
|  | socklen_t* addrlen) = 0; | 
|  | virtual ssize_t sendmsg(int sockfd, const struct msghdr* msg, int flags) = 0; | 
|  | virtual ssize_t sendto(int sockfd, | 
|  | const void* buf, | 
|  | size_t len, | 
|  | int flags, | 
|  | const struct sockaddr* dest_addr, | 
|  | socklen_t addrlen) = 0; | 
|  | virtual int socket(int domain, int type, int protocol) = 0; | 
|  | virtual int setsockopt(int fd, | 
|  | int level, | 
|  | int optname, | 
|  | const void* optval, | 
|  | socklen_t optlen) = 0; | 
|  | virtual ssize_t write(int fd, const void* buf, size_t count) = 0; | 
|  | }; | 
|  |  | 
|  | // It is unfortunate to have R here, but std::result_of cannot be used. | 
|  | template <typename F, typename R, typename... Params> | 
|  | auto SyscallRetryOnError(R r, F f, Params&&... params) | 
|  | -> decltype(f(std::forward<Params>(params)...)) { | 
|  | static_assert( | 
|  | std::is_same<decltype(f(std::forward<Params>(params)...)), R>::value, | 
|  | "Return type does not match"); | 
|  | decltype(f(std::forward<Params>(params)...)) result; | 
|  | do { | 
|  | result = f(std::forward<Params>(params)...); | 
|  | } while (result == r && errno == EINTR); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | template <typename F, typename... Params> | 
|  | auto SyscallRetry(F f, Params&&... params) | 
|  | -> decltype(f(std::forward<Params>(params)...)) { | 
|  | return SyscallRetryOnError(-1, f, std::forward<Params>(params)...); | 
|  | } | 
|  |  | 
|  | template <typename Runner> | 
|  | class ParametrizedKernel final : public KernelInterface { | 
|  | public: | 
|  | static_assert(std::is_trivially_destructible<Runner>::value, | 
|  | "Runner is used as static, must be trivially destructible"); | 
|  |  | 
|  | ~ParametrizedKernel() override {} | 
|  |  | 
|  | int bind(int fd, const struct sockaddr* addr, socklen_t addr_len) override { | 
|  | static Runner syscall("bind"); | 
|  | return syscall.Retry(&::bind, fd, addr, addr_len); | 
|  | } | 
|  | int close(int fd) override { | 
|  | static Runner syscall("close"); | 
|  | return syscall.Retry(&::close, fd); | 
|  | } | 
|  | int ioctl(int fd, int request, void* argp) override { | 
|  | static Runner syscall("ioctl"); | 
|  | return syscall.Retry(&::ioctl, fd, request, argp); | 
|  | } | 
|  | int open(const char* pathname, int flags) override { | 
|  | static Runner syscall("open"); | 
|  | return syscall.Retry(&::open, pathname, flags); | 
|  | } | 
|  | ssize_t read(int fd, void* buf, size_t count) override { | 
|  | static Runner syscall("read"); | 
|  | return syscall.Run(&::read, fd, buf, count); | 
|  | } | 
|  | ssize_t recvfrom(int sockfd, | 
|  | void* buf, | 
|  | size_t len, | 
|  | int flags, | 
|  | struct sockaddr* src_addr, | 
|  | socklen_t* addrlen) override { | 
|  | static Runner syscall("recvfrom"); | 
|  | return syscall.RetryOnError(&::recvfrom, static_cast<ssize_t>(-1), sockfd, | 
|  | buf, len, flags, src_addr, addrlen); | 
|  | } | 
|  | ssize_t sendmsg(int sockfd, const struct msghdr* msg, int flags) override { | 
|  | static Runner syscall("sendmsg"); | 
|  | return syscall.RetryOnError(&::sendmsg, static_cast<ssize_t>(-1), sockfd, | 
|  | msg, flags); | 
|  | } | 
|  | ssize_t sendto(int sockfd, | 
|  | const void* buf, | 
|  | size_t len, | 
|  | int flags, | 
|  | const struct sockaddr* dest_addr, | 
|  | socklen_t addrlen) override { | 
|  | static Runner syscall("sendto"); | 
|  | return syscall.RetryOnError(&::sendto, static_cast<ssize_t>(-1), sockfd, | 
|  | buf, len, flags, dest_addr, addrlen); | 
|  | } | 
|  | int socket(int domain, int type, int protocol) override { | 
|  | static Runner syscall("socket"); | 
|  | return syscall.Retry(&::socket, domain, type, protocol); | 
|  | } | 
|  | int setsockopt(int fd, | 
|  | int level, | 
|  | int optname, | 
|  | const void* optval, | 
|  | socklen_t optlen) override { | 
|  | static Runner syscall("setsockopt"); | 
|  | return syscall.Retry(&::setsockopt, fd, level, optname, optval, optlen); | 
|  | } | 
|  | ssize_t write(int fd, const void* buf, size_t count) override { | 
|  | static Runner syscall("write"); | 
|  | return syscall.Run(&::write, fd, buf, count); | 
|  | } | 
|  | }; | 
|  |  | 
|  | class DefaultKernelRunner { | 
|  | public: | 
|  | explicit DefaultKernelRunner(const char* name) {} | 
|  |  | 
|  | template <typename F, typename R, typename... Params> | 
|  | static auto RetryOnError(F f, R r, Params&&... params) | 
|  | -> decltype(f(std::forward<Params>(params)...)) { | 
|  | return SyscallRetryOnError(r, f, std::forward<Params>(params)...); | 
|  | } | 
|  |  | 
|  | template <typename F, typename... Params> | 
|  | static auto Retry(F f, Params&&... params) | 
|  | -> decltype(f(std::forward<Params>(params)...)) { | 
|  | return SyscallRetry(f, std::forward<Params>(params)...); | 
|  | } | 
|  |  | 
|  | template <typename F, typename... Params> | 
|  | static auto Run(F f, Params&&... params) | 
|  | -> decltype(f(std::forward<Params>(params)...)) { | 
|  | return f(std::forward<Params>(params)...); | 
|  | } | 
|  | }; | 
|  |  | 
|  | using Kernel = ParametrizedKernel<DefaultKernelRunner>; | 
|  |  | 
|  | }  // namespace quic | 
|  |  | 
|  | #endif  // QUICHE_QUIC_QBONE_PLATFORM_KERNEL_INTERFACE_H_ |