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>
syscallRetry(FnT fn,Params &&...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
open(const std::string & pathname,int flags,mode_t mode) const44 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
socket(int domain,int type,int protocol) const52 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
getsockname(Fd sock,sockaddr * addr,socklen_t * addrlen) const60 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
setsockopt(Fd sock,int level,int optname,const void * optval,socklen_t optlen) const68 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
bind(Fd sock,const sockaddr * addr,socklen_t addrlen) const77 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
connect(Fd sock,const sockaddr * addr,socklen_t addrlen) const85 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
eventfd(unsigned int initval,int flags) const93 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
ppoll(pollfd * fds,nfds_t nfds,double timeout) const101 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
write(Fd fd,const Slice buf) const112 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
read(Fd fd,const Slice buf) const120 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
sendto(Fd sock,const Slice buf,int flags,const sockaddr * dst,socklen_t dstlen) const128 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
recvfrom(Fd sock,const Slice dst,int flags,sockaddr * src,socklen_t * srclen) const137 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
shutdown(Fd fd,int how) const149 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
close(Fd fd) const157 Status close(Fd fd) const override {
158 auto rv = ::close(fd.get());
159 if (rv == -1) {
160 return statusFromErrno(errno, "close() failed");
161 }
162 return status::ok;
163 }
164
fopen(const std::string & path,const std::string & mode) const165 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
fork() const173 StatusOr<pid_t> fork() const override {
174 pid_t rv = ::fork();
175 if (rv == -1) {
176 return statusFromErrno(errno, "fork() failed");
177 }
178 return rv;
179 }
180
vfprintf(FILE * file,const char * format,va_list ap) const181 StatusOr<int> vfprintf(FILE* file, const char* format, va_list ap) const override {
182 auto rv = ::vfprintf(file, format, ap);
183 if (rv == -1) {
184 return statusFromErrno(errno, "vfprintf() failed");
185 }
186 return rv;
187 }
188
vfscanf(FILE * file,const char * format,va_list ap) const189 StatusOr<int> vfscanf(FILE* file, const char* format, va_list ap) const override {
190 auto rv = ::vfscanf(file, format, ap);
191 if (rv == -1) {
192 return statusFromErrno(errno, "vfscanf() failed");
193 }
194 return rv;
195 }
196
fclose(FILE * file) const197 Status fclose(FILE* file) const override {
198 auto rv = ::fclose(file);
199 if (rv == -1) {
200 return statusFromErrno(errno, "fclose() failed");
201 }
202 return status::ok;
203 }
204 };
205
~SyscallsHolder()206 SyscallsHolder::~SyscallsHolder() {
207 delete &get();
208 }
209
get()210 Syscalls& SyscallsHolder::get() {
211 while (true) {
212 // memory_order_relaxed gives the compiler and hardware more
213 // freedom. If we get a stale value (this should only happen
214 // early in the execution of a program) the exchange code below
215 // will loop until we get the most current value.
216 auto* syscalls = mSyscalls.load(std::memory_order_relaxed);
217 // Common case returns existing syscalls
218 if (syscalls) {
219 return *syscalls;
220 }
221
222 // This code will execute on first get()
223 std::unique_ptr<Syscalls> tmp(new RealSyscalls());
224 Syscalls* expected = nullptr;
225 bool success = mSyscalls.compare_exchange_strong(expected, tmp.get());
226 if (success) {
227 // Ownership was transferred to mSyscalls already, must release()
228 return *tmp.release();
229 }
230 }
231 }
232
swap(Syscalls & syscalls)233 Syscalls& SyscallsHolder::swap(Syscalls& syscalls) {
234 return *mSyscalls.exchange(&syscalls);
235 }
236
237 SyscallsHolder sSyscalls;
238
239 } // namespace netdutils
240 } // namespace android
241