Home | History | Annotate | Download | only in libnetdutils
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <atomic>
     18 #include <type_traits>
     19 #include <utility>
     20 
     21 #include "netdutils/Syscalls.h"
     22 
     23 namespace android {
     24 namespace netdutils {
     25 namespace {
     26 
     27 // Retry syscall fn as long as it returns -1 with errno == EINTR
     28 template <typename FnT, typename... Params>
     29 typename std::result_of<FnT(Params...)>::type syscallRetry(FnT fn, Params&&... params) {
     30     auto rv = fn(std::forward<Params>(params)...);
     31     while ((rv == -1) && (errno == EINTR)) {
     32         rv = fn(std::forward<Params>(params)...);
     33     }
     34     return rv;
     35 }
     36 
     37 }  // namespace
     38 
     39 // Production implementation of Syscalls that forwards to libc syscalls.
     40 class RealSyscalls final : public Syscalls {
     41   public:
     42     ~RealSyscalls() override = default;
     43 
     44     StatusOr<UniqueFd> open(const std::string& pathname, int flags, mode_t mode) const override {
     45         UniqueFd fd(::open(pathname.c_str(), flags, mode));
     46         if (!isWellFormed(fd)) {
     47             return statusFromErrno(errno, "open(\"" + pathname + "\"...) failed");
     48         }
     49         return fd;
     50     }
     51 
     52     StatusOr<UniqueFd> socket(int domain, int type, int protocol) const override {
     53         UniqueFd sock(::socket(domain, type, protocol));
     54         if (!isWellFormed(sock)) {
     55             return statusFromErrno(errno, "socket() failed");
     56         }
     57         return sock;
     58     }
     59 
     60     Status getsockname(Fd sock, sockaddr* addr, socklen_t* addrlen) const override {
     61         auto rv = ::getsockname(sock.get(), addr, addrlen);
     62         if (rv == -1) {
     63             return statusFromErrno(errno, "getsockname() failed");
     64         }
     65         return status::ok;
     66     }
     67 
     68     Status getsockopt(Fd sock, int level, int optname, void* optval,
     69                       socklen_t* optlen) const override {
     70         auto rv = ::getsockopt(sock.get(), level, optname, optval, optlen);
     71         if (rv == -1) {
     72             return statusFromErrno(errno, "getsockopt() failed");
     73         }
     74         return status::ok;
     75     }
     76 
     77     Status setsockopt(Fd sock, int level, int optname, const void* optval,
     78                       socklen_t optlen) const override {
     79         auto rv = ::setsockopt(sock.get(), level, optname, optval, optlen);
     80         if (rv == -1) {
     81             return statusFromErrno(errno, "setsockopt() failed");
     82         }
     83         return status::ok;
     84     }
     85 
     86     Status bind(Fd sock, const sockaddr* addr, socklen_t addrlen) const override {
     87         auto rv = ::bind(sock.get(), addr, addrlen);
     88         if (rv == -1) {
     89             return statusFromErrno(errno, "bind() failed");
     90         }
     91         return status::ok;
     92     }
     93 
     94     Status connect(Fd sock, const sockaddr* addr, socklen_t addrlen) const override {
     95         auto rv = syscallRetry(::connect, sock.get(), addr, addrlen);
     96         if (rv == -1) {
     97             return statusFromErrno(errno, "connect() failed");
     98         }
     99         return status::ok;
    100     }
    101 
    102     StatusOr<UniqueFd> eventfd(unsigned int initval, int flags) const override {
    103         UniqueFd fd(::eventfd(initval, flags));
    104         if (!isWellFormed(fd)) {
    105             return statusFromErrno(errno, "eventfd() failed");
    106         }
    107         return fd;
    108     }
    109 
    110     StatusOr<int> ppoll(pollfd* fds, nfds_t nfds, double timeout) const override {
    111         timespec ts = {};
    112         ts.tv_sec = timeout;
    113         ts.tv_nsec = (timeout - ts.tv_sec) * 1e9;
    114         auto rv = syscallRetry(::ppoll, fds, nfds, &ts, nullptr);
    115         if (rv == -1) {
    116             return statusFromErrno(errno, "ppoll() failed");
    117         }
    118         return rv;
    119     }
    120 
    121     StatusOr<size_t> writev(Fd fd, const std::vector<iovec>& iov) const override {
    122         auto rv = syscallRetry(::writev, fd.get(), iov.data(), iov.size());
    123         if (rv == -1) {
    124             return statusFromErrno(errno, "writev() failed");
    125         }
    126         return rv;
    127     }
    128 
    129     StatusOr<size_t> write(Fd fd, const Slice buf) const override {
    130         auto rv = syscallRetry(::write, fd.get(), buf.base(), buf.size());
    131         if (rv == -1) {
    132             return statusFromErrno(errno, "write() failed");
    133         }
    134         return static_cast<size_t>(rv);
    135     }
    136 
    137     StatusOr<Slice> read(Fd fd, const Slice buf) const override {
    138         auto rv = syscallRetry(::read, fd.get(), buf.base(), buf.size());
    139         if (rv == -1) {
    140             return statusFromErrno(errno, "read() failed");
    141         }
    142         return Slice(buf.base(), rv);
    143     }
    144 
    145     StatusOr<size_t> sendto(Fd sock, const Slice buf, int flags, const sockaddr* dst,
    146                             socklen_t dstlen) const override {
    147         auto rv = syscallRetry(::sendto, sock.get(), buf.base(), buf.size(), flags, dst, dstlen);
    148         if (rv == -1) {
    149             return statusFromErrno(errno, "sendto() failed");
    150         }
    151         return static_cast<size_t>(rv);
    152     }
    153 
    154     StatusOr<Slice> recvfrom(Fd sock, const Slice dst, int flags, sockaddr* src,
    155                              socklen_t* srclen) const override {
    156         auto rv = syscallRetry(::recvfrom, sock.get(), dst.base(), dst.size(), flags, src, srclen);
    157         if (rv == -1) {
    158             return statusFromErrno(errno, "recvfrom() failed");
    159         }
    160         if (rv == 0) {
    161             return status::eof;
    162         }
    163         return take(dst, rv);
    164     }
    165 
    166     Status shutdown(Fd fd, int how) const override {
    167         auto rv = ::shutdown(fd.get(), how);
    168         if (rv == -1) {
    169             return statusFromErrno(errno, "shutdown() failed");
    170         }
    171         return status::ok;
    172     }
    173 
    174     Status close(Fd fd) const override {
    175         auto rv = ::close(fd.get());
    176         if (rv == -1) {
    177             return statusFromErrno(errno, "close() failed");
    178         }
    179         return status::ok;
    180     }
    181 
    182     StatusOr<UniqueFile> fopen(const std::string& path, const std::string& mode) const override {
    183         UniqueFile file(::fopen(path.c_str(), mode.c_str()));
    184         if (file == NULL) {
    185             return statusFromErrno(errno, "fopen(\"" + path + "\", \"" + mode + "\") failed");
    186         }
    187         return file;
    188     }
    189 
    190     StatusOr<pid_t> fork() const override {
    191         pid_t rv = ::fork();
    192         if (rv == -1) {
    193             return statusFromErrno(errno, "fork() failed");
    194         }
    195         return rv;
    196     }
    197 
    198     StatusOr<int> vfprintf(FILE* file, const char* format, va_list ap) const override {
    199         auto rv = ::vfprintf(file, format, ap);
    200         if (rv == -1) {
    201             return statusFromErrno(errno, "vfprintf() failed");
    202         }
    203         return rv;
    204     }
    205 
    206     StatusOr<int> vfscanf(FILE* file, const char* format, va_list ap) const override {
    207         auto rv = ::vfscanf(file, format, ap);
    208         if (rv == -1) {
    209             return statusFromErrno(errno, "vfscanf() failed");
    210         }
    211         return rv;
    212     }
    213 
    214     Status fclose(FILE* file) const override {
    215         auto rv = ::fclose(file);
    216         if (rv == -1) {
    217             return statusFromErrno(errno, "fclose() failed");
    218         }
    219         return status::ok;
    220     }
    221 };
    222 
    223 SyscallsHolder::~SyscallsHolder() {
    224     delete &get();
    225 }
    226 
    227 Syscalls& SyscallsHolder::get() {
    228     while (true) {
    229         // memory_order_relaxed gives the compiler and hardware more
    230         // freedom. If we get a stale value (this should only happen
    231         // early in the execution of a program) the exchange code below
    232         // will loop until we get the most current value.
    233         auto* syscalls = mSyscalls.load(std::memory_order_relaxed);
    234         // Common case returns existing syscalls
    235         if (syscalls) {
    236             return *syscalls;
    237         }
    238 
    239         // This code will execute on first get()
    240         std::unique_ptr<Syscalls> tmp(new RealSyscalls());
    241         Syscalls* expected = nullptr;
    242         bool success = mSyscalls.compare_exchange_strong(expected, tmp.get());
    243         if (success) {
    244             // Ownership was transferred to mSyscalls already, must release()
    245             return *tmp.release();
    246         }
    247     }
    248 }
    249 
    250 Syscalls& SyscallsHolder::swap(Syscalls& syscalls) {
    251     return *mSyscalls.exchange(&syscalls);
    252 }
    253 
    254 SyscallsHolder sSyscalls;
    255 
    256 }  // namespace netdutils
    257 }  // namespace android
    258