| // 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_ |