blob: 53543417310f8e89013d851f4f6b1452b3851947 [file] [log] [blame]
Joel Scherpelzf3fa5cc2017-05-22 12:30:03 +09001/*
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
23namespace android {
24namespace netdutils {
25namespace {
26
27// Retry syscall fn as long as it returns -1 with errno == EINTR
28template <typename FnT, typename... Params>
29typename 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.
40class RealSyscalls final : public Syscalls {
41 public:
42 ~RealSyscalls() override = default;
43
Joel Scherpelzde937962017-06-01 13:20:21 +090044 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
Joel Scherpelzf3fa5cc2017-05-22 12:30:03 +090052 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 setsockopt(Fd sock, int level, int optname, const void* optval,
69 socklen_t optlen) const override {
70 auto rv = ::setsockopt(sock.get(), level, optname, optval, optlen);
71 if (rv == -1) {
72 return statusFromErrno(errno, "setsockopt() failed");
73 }
74 return status::ok;
75 }
76
77 Status bind(Fd sock, const sockaddr* addr, socklen_t addrlen) const override {
78 auto rv = ::bind(sock.get(), addr, addrlen);
79 if (rv == -1) {
80 return statusFromErrno(errno, "bind() failed");
81 }
82 return status::ok;
83 }
84
85 Status connect(Fd sock, const sockaddr* addr, socklen_t addrlen) const override {
86 auto rv = syscallRetry(::connect, sock.get(), addr, addrlen);
87 if (rv == -1) {
88 return statusFromErrno(errno, "connect() failed");
89 }
90 return status::ok;
91 }
92
93 StatusOr<UniqueFd> eventfd(unsigned int initval, int flags) const override {
94 UniqueFd fd(::eventfd(initval, flags));
95 if (!isWellFormed(fd)) {
96 return statusFromErrno(errno, "eventfd() failed");
97 }
98 return fd;
99 }
100
101 StatusOr<int> ppoll(pollfd* fds, nfds_t nfds, double timeout) const override {
102 timespec ts = {};
103 ts.tv_sec = timeout;
104 ts.tv_nsec = (timeout - ts.tv_sec) * 1e9;
105 auto rv = syscallRetry(::ppoll, fds, nfds, &ts, nullptr);
106 if (rv == -1) {
107 return statusFromErrno(errno, "ppoll() failed");
108 }
109 return rv;
110 }
111
ludi4072ff22017-06-15 08:56:52 -0700112 StatusOr<size_t> writev(Fd fd, const std::vector<iovec>& iov) const override {
113 auto rv = syscallRetry(::writev, fd.get(), iov.data(), iov.size());
114 if (rv == -1) {
115 return statusFromErrno(errno, "writev() failed");
116 }
117 return rv;
118 }
119
Joel Scherpelzf3fa5cc2017-05-22 12:30:03 +0900120 StatusOr<size_t> write(Fd fd, const Slice buf) const override {
121 auto rv = syscallRetry(::write, fd.get(), buf.base(), buf.size());
122 if (rv == -1) {
123 return statusFromErrno(errno, "write() failed");
124 }
125 return static_cast<size_t>(rv);
126 }
127
128 StatusOr<Slice> read(Fd fd, const Slice buf) const override {
129 auto rv = syscallRetry(::read, fd.get(), buf.base(), buf.size());
130 if (rv == -1) {
131 return statusFromErrno(errno, "read() failed");
132 }
133 return Slice(buf.base(), rv);
134 }
135
136 StatusOr<size_t> sendto(Fd sock, const Slice buf, int flags, const sockaddr* dst,
137 socklen_t dstlen) const override {
138 auto rv = syscallRetry(::sendto, sock.get(), buf.base(), buf.size(), flags, dst, dstlen);
139 if (rv == -1) {
140 return statusFromErrno(errno, "sendto() failed");
141 }
142 return static_cast<size_t>(rv);
143 }
144
145 StatusOr<Slice> recvfrom(Fd sock, const Slice dst, int flags, sockaddr* src,
146 socklen_t* srclen) const override {
147 auto rv = syscallRetry(::recvfrom, sock.get(), dst.base(), dst.size(), flags, src, srclen);
148 if (rv == -1) {
149 return statusFromErrno(errno, "recvfrom() failed");
150 }
151 if (rv == 0) {
152 return status::eof;
153 }
154 return take(dst, rv);
155 }
156
157 Status shutdown(Fd fd, int how) const override {
158 auto rv = ::shutdown(fd.get(), how);
159 if (rv == -1) {
160 return statusFromErrno(errno, "shutdown() failed");
161 }
162 return status::ok;
163 }
164
165 Status close(Fd fd) const override {
166 auto rv = ::close(fd.get());
167 if (rv == -1) {
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900168 return statusFromErrno(errno, "close() failed");
169 }
170 return status::ok;
171 }
172
173 StatusOr<UniqueFile> fopen(const std::string& path, const std::string& mode) const override {
174 UniqueFile file(::fopen(path.c_str(), mode.c_str()));
175 if (file == NULL) {
176 return statusFromErrno(errno, "fopen(\"" + path + "\", \"" + mode + "\") failed");
177 }
178 return file;
179 }
180
Lorenzo Colitti2103b6b2017-08-14 11:38:18 +0900181 StatusOr<pid_t> fork() const override {
182 pid_t rv = ::fork();
183 if (rv == -1) {
184 return statusFromErrno(errno, "fork() failed");
185 }
186 return rv;
187 }
188
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900189 StatusOr<int> vfprintf(FILE* file, const char* format, va_list ap) const override {
190 auto rv = ::vfprintf(file, format, ap);
191 if (rv == -1) {
192 return statusFromErrno(errno, "vfprintf() failed");
193 }
194 return rv;
195 }
196
197 StatusOr<int> vfscanf(FILE* file, const char* format, va_list ap) const override {
198 auto rv = ::vfscanf(file, format, ap);
199 if (rv == -1) {
200 return statusFromErrno(errno, "vfscanf() failed");
201 }
202 return rv;
203 }
204
205 Status fclose(FILE* file) const override {
206 auto rv = ::fclose(file);
207 if (rv == -1) {
208 return statusFromErrno(errno, "fclose() failed");
Joel Scherpelzf3fa5cc2017-05-22 12:30:03 +0900209 }
210 return status::ok;
211 }
212};
213
214SyscallsHolder::~SyscallsHolder() {
215 delete &get();
216}
217
218Syscalls& SyscallsHolder::get() {
219 while (true) {
220 // memory_order_relaxed gives the compiler and hardware more
221 // freedom. If we get a stale value (this should only happen
222 // early in the execution of a program) the exchange code below
223 // will loop until we get the most current value.
224 auto* syscalls = mSyscalls.load(std::memory_order_relaxed);
225 // Common case returns existing syscalls
226 if (syscalls) {
227 return *syscalls;
228 }
229
230 // This code will execute on first get()
231 std::unique_ptr<Syscalls> tmp(new RealSyscalls());
232 Syscalls* expected = nullptr;
233 bool success = mSyscalls.compare_exchange_strong(expected, tmp.get());
234 if (success) {
235 // Ownership was transferred to mSyscalls already, must release()
236 return *tmp.release();
237 }
238 }
239}
240
241Syscalls& SyscallsHolder::swap(Syscalls& syscalls) {
242 return *mSyscalls.exchange(&syscalls);
243}
244
245SyscallsHolder sSyscalls;
246
247} // namespace netdutils
248} // namespace android