blob: 7e1a2426350ac58a0a1845b9dff38faaa56e963b [file] [log] [blame]
Ken Chen38cf6982021-10-21 22:18:59 +08001/*
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
23namespace android {
24namespace netdutils {
25namespace {
26
27// Retry syscall fn as long as it returns -1 with errno == EINTR
28template <typename FnT, typename... Params>
Ryan Prichard8cbe32c2022-08-26 20:31:55 -070029typename std::invoke_result<FnT, Params...>::type syscallRetry(FnT fn, Params&&... params) {
Ken Chen38cf6982021-10-21 22:18:59 +080030 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.
40class 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
231SyscallsHolder::~SyscallsHolder() {
232 delete &get();
233}
234
235Syscalls& 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
258Syscalls& SyscallsHolder::swap(Syscalls& syscalls) {
259 return *mSyscalls.exchange(&syscalls);
260}
261
262SyscallsHolder sSyscalls;
263
264} // namespace netdutils
265} // namespace android