| Ken Chen | 38cf698 | 2021-10-21 22:18:59 +0800 | [diff] [blame] | 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 "netdutils/Syscalls.h" | 
 | 18 |  | 
 | 19 | #include <atomic> | 
 | 20 | #include <type_traits> | 
 | 21 | #include <utility> | 
 | 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> | 
| Ryan Prichard | 8cbe32c | 2022-08-26 20:31:55 -0700 | [diff] [blame] | 29 | typename std::invoke_result<FnT, Params...>::type syscallRetry(FnT fn, Params&&... params) { | 
| Ken Chen | 38cf698 | 2021-10-21 22:18:59 +0800 | [diff] [blame] | 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<ifreq> ioctl(Fd sock, unsigned long request, ifreq* ifr) const override { | 
 | 103 |         auto rv = ::ioctl(sock.get(), request, ifr); | 
 | 104 |         if (rv == -1) { | 
 | 105 |             return statusFromErrno(errno, "ioctl() failed"); | 
 | 106 |         } | 
 | 107 |         return *ifr; | 
 | 108 |     } | 
 | 109 |  | 
 | 110 |     StatusOr<UniqueFd> eventfd(unsigned int initval, int flags) const override { | 
 | 111 |         UniqueFd fd(::eventfd(initval, flags)); | 
 | 112 |         if (!isWellFormed(fd)) { | 
 | 113 |             return statusFromErrno(errno, "eventfd() failed"); | 
 | 114 |         } | 
 | 115 |         return fd; | 
 | 116 |     } | 
 | 117 |  | 
 | 118 |     StatusOr<int> ppoll(pollfd* fds, nfds_t nfds, double timeout) const override { | 
 | 119 |         timespec ts = {}; | 
 | 120 |         ts.tv_sec = timeout; | 
 | 121 |         ts.tv_nsec = (timeout - ts.tv_sec) * 1e9; | 
 | 122 |         auto rv = syscallRetry(::ppoll, fds, nfds, &ts, nullptr); | 
 | 123 |         if (rv == -1) { | 
 | 124 |             return statusFromErrno(errno, "ppoll() failed"); | 
 | 125 |         } | 
 | 126 |         return rv; | 
 | 127 |     } | 
 | 128 |  | 
 | 129 |     StatusOr<size_t> writev(Fd fd, const std::vector<iovec>& iov) const override { | 
 | 130 |         auto rv = syscallRetry(::writev, fd.get(), iov.data(), iov.size()); | 
 | 131 |         if (rv == -1) { | 
 | 132 |             return statusFromErrno(errno, "writev() failed"); | 
 | 133 |         } | 
 | 134 |         return rv; | 
 | 135 |     } | 
 | 136 |  | 
 | 137 |     StatusOr<size_t> write(Fd fd, const Slice buf) const override { | 
 | 138 |         auto rv = syscallRetry(::write, fd.get(), buf.base(), buf.size()); | 
 | 139 |         if (rv == -1) { | 
 | 140 |             return statusFromErrno(errno, "write() failed"); | 
 | 141 |         } | 
 | 142 |         return static_cast<size_t>(rv); | 
 | 143 |     } | 
 | 144 |  | 
 | 145 |     StatusOr<Slice> read(Fd fd, const Slice buf) const override { | 
 | 146 |         auto rv = syscallRetry(::read, fd.get(), buf.base(), buf.size()); | 
 | 147 |         if (rv == -1) { | 
 | 148 |             return statusFromErrno(errno, "read() failed"); | 
 | 149 |         } | 
 | 150 |         return Slice(buf.base(), rv); | 
 | 151 |     } | 
 | 152 |  | 
 | 153 |     StatusOr<size_t> sendto(Fd sock, const Slice buf, int flags, const sockaddr* dst, | 
 | 154 |                             socklen_t dstlen) const override { | 
 | 155 |         auto rv = syscallRetry(::sendto, sock.get(), buf.base(), buf.size(), flags, dst, dstlen); | 
 | 156 |         if (rv == -1) { | 
 | 157 |             return statusFromErrno(errno, "sendto() failed"); | 
 | 158 |         } | 
 | 159 |         return static_cast<size_t>(rv); | 
 | 160 |     } | 
 | 161 |  | 
 | 162 |     StatusOr<Slice> recvfrom(Fd sock, const Slice dst, int flags, sockaddr* src, | 
 | 163 |                              socklen_t* srclen) const override { | 
 | 164 |         auto rv = syscallRetry(::recvfrom, sock.get(), dst.base(), dst.size(), flags, src, srclen); | 
 | 165 |         if (rv == -1) { | 
 | 166 |             return statusFromErrno(errno, "recvfrom() failed"); | 
 | 167 |         } | 
 | 168 |         if (rv == 0) { | 
 | 169 |             return status::eof; | 
 | 170 |         } | 
 | 171 |         return take(dst, rv); | 
 | 172 |     } | 
 | 173 |  | 
 | 174 |     Status shutdown(Fd fd, int how) const override { | 
 | 175 |         auto rv = ::shutdown(fd.get(), how); | 
 | 176 |         if (rv == -1) { | 
 | 177 |             return statusFromErrno(errno, "shutdown() failed"); | 
 | 178 |         } | 
 | 179 |         return status::ok; | 
 | 180 |     } | 
 | 181 |  | 
 | 182 |     Status close(Fd fd) const override { | 
 | 183 |         auto rv = ::close(fd.get()); | 
 | 184 |         if (rv == -1) { | 
 | 185 |             return statusFromErrno(errno, "close() failed"); | 
 | 186 |         } | 
 | 187 |         return status::ok; | 
 | 188 |     } | 
 | 189 |  | 
 | 190 |     StatusOr<UniqueFile> fopen(const std::string& path, const std::string& mode) const override { | 
 | 191 |         UniqueFile file(::fopen(path.c_str(), mode.c_str())); | 
 | 192 |         if (file == nullptr) { | 
 | 193 |             return statusFromErrno(errno, "fopen(\"" + path + "\", \"" + mode + "\") failed"); | 
 | 194 |         } | 
 | 195 |         return file; | 
 | 196 |     } | 
 | 197 |  | 
 | 198 |     StatusOr<pid_t> fork() const override { | 
 | 199 |         pid_t rv = ::fork(); | 
 | 200 |         if (rv == -1) { | 
 | 201 |             return statusFromErrno(errno, "fork() failed"); | 
 | 202 |         } | 
 | 203 |         return rv; | 
 | 204 |     } | 
 | 205 |  | 
 | 206 |     StatusOr<int> vfprintf(FILE* file, const char* format, va_list ap) const override { | 
 | 207 |         auto rv = ::vfprintf(file, format, ap); | 
 | 208 |         if (rv == -1) { | 
 | 209 |             return statusFromErrno(errno, "vfprintf() failed"); | 
 | 210 |         } | 
 | 211 |         return rv; | 
 | 212 |     } | 
 | 213 |  | 
 | 214 |     StatusOr<int> vfscanf(FILE* file, const char* format, va_list ap) const override { | 
 | 215 |         auto rv = ::vfscanf(file, format, ap); | 
 | 216 |         if (rv == -1) { | 
 | 217 |             return statusFromErrno(errno, "vfscanf() failed"); | 
 | 218 |         } | 
 | 219 |         return rv; | 
 | 220 |     } | 
 | 221 |  | 
 | 222 |     Status fclose(FILE* file) const override { | 
 | 223 |         auto rv = ::fclose(file); | 
 | 224 |         if (rv == -1) { | 
 | 225 |             return statusFromErrno(errno, "fclose() failed"); | 
 | 226 |         } | 
 | 227 |         return status::ok; | 
 | 228 |     } | 
 | 229 | }; | 
 | 230 |  | 
 | 231 | SyscallsHolder::~SyscallsHolder() { | 
 | 232 |     delete &get(); | 
 | 233 | } | 
 | 234 |  | 
 | 235 | Syscalls& SyscallsHolder::get() { | 
 | 236 |     while (true) { | 
 | 237 |         // memory_order_relaxed gives the compiler and hardware more | 
 | 238 |         // freedom. If we get a stale value (this should only happen | 
 | 239 |         // early in the execution of a program) the exchange code below | 
 | 240 |         // will loop until we get the most current value. | 
 | 241 |         auto* syscalls = mSyscalls.load(std::memory_order_relaxed); | 
 | 242 |         // Common case returns existing syscalls | 
 | 243 |         if (syscalls) { | 
 | 244 |             return *syscalls; | 
 | 245 |         } | 
 | 246 |  | 
 | 247 |         // This code will execute on first get() | 
 | 248 |         std::unique_ptr<Syscalls> tmp(new RealSyscalls()); | 
 | 249 |         Syscalls* expected = nullptr; | 
 | 250 |         bool success = mSyscalls.compare_exchange_strong(expected, tmp.get()); | 
 | 251 |         if (success) { | 
 | 252 |             // Ownership was transferred to mSyscalls already, must release() | 
 | 253 |             return *tmp.release(); | 
 | 254 |         } | 
 | 255 |     } | 
 | 256 | } | 
 | 257 |  | 
 | 258 | Syscalls& SyscallsHolder::swap(Syscalls& syscalls) { | 
 | 259 |     return *mSyscalls.exchange(&syscalls); | 
 | 260 | } | 
 | 261 |  | 
 | 262 | SyscallsHolder sSyscalls; | 
 | 263 |  | 
 | 264 | }  // namespace netdutils | 
 | 265 | }  // namespace android |