blob: 00e2422a68efca3f6ed45b710c5f428ab5762e90 [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
112 StatusOr<size_t> write(Fd fd, const Slice buf) const override {
113 auto rv = syscallRetry(::write, fd.get(), buf.base(), buf.size());
114 if (rv == -1) {
115 return statusFromErrno(errno, "write() failed");
116 }
117 return static_cast<size_t>(rv);
118 }
119
120 StatusOr<Slice> read(Fd fd, const Slice buf) const override {
121 auto rv = syscallRetry(::read, fd.get(), buf.base(), buf.size());
122 if (rv == -1) {
123 return statusFromErrno(errno, "read() failed");
124 }
125 return Slice(buf.base(), rv);
126 }
127
128 StatusOr<size_t> sendto(Fd sock, const Slice buf, int flags, const sockaddr* dst,
129 socklen_t dstlen) const override {
130 auto rv = syscallRetry(::sendto, sock.get(), buf.base(), buf.size(), flags, dst, dstlen);
131 if (rv == -1) {
132 return statusFromErrno(errno, "sendto() failed");
133 }
134 return static_cast<size_t>(rv);
135 }
136
137 StatusOr<Slice> recvfrom(Fd sock, const Slice dst, int flags, sockaddr* src,
138 socklen_t* srclen) const override {
139 auto rv = syscallRetry(::recvfrom, sock.get(), dst.base(), dst.size(), flags, src, srclen);
140 if (rv == -1) {
141 return statusFromErrno(errno, "recvfrom() failed");
142 }
143 if (rv == 0) {
144 return status::eof;
145 }
146 return take(dst, rv);
147 }
148
149 Status shutdown(Fd fd, int how) const override {
150 auto rv = ::shutdown(fd.get(), how);
151 if (rv == -1) {
152 return statusFromErrno(errno, "shutdown() failed");
153 }
154 return status::ok;
155 }
156
157 Status close(Fd fd) const override {
158 auto rv = ::close(fd.get());
159 if (rv == -1) {
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900160 return statusFromErrno(errno, "close() failed");
161 }
162 return status::ok;
163 }
164
165 StatusOr<UniqueFile> fopen(const std::string& path, const std::string& mode) const override {
166 UniqueFile file(::fopen(path.c_str(), mode.c_str()));
167 if (file == NULL) {
168 return statusFromErrno(errno, "fopen(\"" + path + "\", \"" + mode + "\") failed");
169 }
170 return file;
171 }
172
173 StatusOr<int> vfprintf(FILE* file, const char* format, va_list ap) const override {
174 auto rv = ::vfprintf(file, format, ap);
175 if (rv == -1) {
176 return statusFromErrno(errno, "vfprintf() failed");
177 }
178 return rv;
179 }
180
181 StatusOr<int> vfscanf(FILE* file, const char* format, va_list ap) const override {
182 auto rv = ::vfscanf(file, format, ap);
183 if (rv == -1) {
184 return statusFromErrno(errno, "vfscanf() failed");
185 }
186 return rv;
187 }
188
189 Status fclose(FILE* file) const override {
190 auto rv = ::fclose(file);
191 if (rv == -1) {
192 return statusFromErrno(errno, "fclose() failed");
Joel Scherpelzf3fa5cc2017-05-22 12:30:03 +0900193 }
194 return status::ok;
195 }
196};
197
198SyscallsHolder::~SyscallsHolder() {
199 delete &get();
200}
201
202Syscalls& SyscallsHolder::get() {
203 while (true) {
204 // memory_order_relaxed gives the compiler and hardware more
205 // freedom. If we get a stale value (this should only happen
206 // early in the execution of a program) the exchange code below
207 // will loop until we get the most current value.
208 auto* syscalls = mSyscalls.load(std::memory_order_relaxed);
209 // Common case returns existing syscalls
210 if (syscalls) {
211 return *syscalls;
212 }
213
214 // This code will execute on first get()
215 std::unique_ptr<Syscalls> tmp(new RealSyscalls());
216 Syscalls* expected = nullptr;
217 bool success = mSyscalls.compare_exchange_strong(expected, tmp.get());
218 if (success) {
219 // Ownership was transferred to mSyscalls already, must release()
220 return *tmp.release();
221 }
222 }
223}
224
225Syscalls& SyscallsHolder::swap(Syscalls& syscalls) {
226 return *mSyscalls.exchange(&syscalls);
227}
228
229SyscallsHolder sSyscalls;
230
231} // namespace netdutils
232} // namespace android