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 
getsockopt(Fd sock,int level,int optname,void * optval,socklen_t * optlen) const68     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 
setsockopt(Fd sock,int level,int optname,const void * optval,socklen_t optlen) const77     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 
bind(Fd sock,const sockaddr * addr,socklen_t addrlen) const86     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 
connect(Fd sock,const sockaddr * addr,socklen_t addrlen) const94     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 
eventfd(unsigned int initval,int flags) const102     StatusOr<UniqueFd> eventfd(unsigned int initval, int flags) const override {
103         UniqueFd fd(::eventfd(initval, flags));
104         if (!isWellFormed(fd)) {
105             return statusFromErrno(errno, "eventfd() failed");
106         }
107         return fd;
108     }
109 
ppoll(pollfd * fds,nfds_t nfds,double timeout) const110     StatusOr<int> ppoll(pollfd* fds, nfds_t nfds, double timeout) const override {
111         timespec ts = {};
112         ts.tv_sec = timeout;
113         ts.tv_nsec = (timeout - ts.tv_sec) * 1e9;
114         auto rv = syscallRetry(::ppoll, fds, nfds, &ts, nullptr);
115         if (rv == -1) {
116             return statusFromErrno(errno, "ppoll() failed");
117         }
118         return rv;
119     }
120 
writev(Fd fd,const std::vector<iovec> & iov) const121     StatusOr<size_t> writev(Fd fd, const std::vector<iovec>& iov) const override {
122         auto rv = syscallRetry(::writev, fd.get(), iov.data(), iov.size());
123         if (rv == -1) {
124             return statusFromErrno(errno, "writev() failed");
125         }
126         return rv;
127     }
128 
write(Fd fd,const Slice buf) const129     StatusOr<size_t> write(Fd fd, const Slice buf) const override {
130         auto rv = syscallRetry(::write, fd.get(), buf.base(), buf.size());
131         if (rv == -1) {
132             return statusFromErrno(errno, "write() failed");
133         }
134         return static_cast<size_t>(rv);
135     }
136 
read(Fd fd,const Slice buf) const137     StatusOr<Slice> read(Fd fd, const Slice buf) const override {
138         auto rv = syscallRetry(::read, fd.get(), buf.base(), buf.size());
139         if (rv == -1) {
140             return statusFromErrno(errno, "read() failed");
141         }
142         return Slice(buf.base(), rv);
143     }
144 
sendto(Fd sock,const Slice buf,int flags,const sockaddr * dst,socklen_t dstlen) const145     StatusOr<size_t> sendto(Fd sock, const Slice buf, int flags, const sockaddr* dst,
146                             socklen_t dstlen) const override {
147         auto rv = syscallRetry(::sendto, sock.get(), buf.base(), buf.size(), flags, dst, dstlen);
148         if (rv == -1) {
149             return statusFromErrno(errno, "sendto() failed");
150         }
151         return static_cast<size_t>(rv);
152     }
153 
recvfrom(Fd sock,const Slice dst,int flags,sockaddr * src,socklen_t * srclen) const154     StatusOr<Slice> recvfrom(Fd sock, const Slice dst, int flags, sockaddr* src,
155                              socklen_t* srclen) const override {
156         auto rv = syscallRetry(::recvfrom, sock.get(), dst.base(), dst.size(), flags, src, srclen);
157         if (rv == -1) {
158             return statusFromErrno(errno, "recvfrom() failed");
159         }
160         if (rv == 0) {
161             return status::eof;
162         }
163         return take(dst, rv);
164     }
165 
shutdown(Fd fd,int how) const166     Status shutdown(Fd fd, int how) const override {
167         auto rv = ::shutdown(fd.get(), how);
168         if (rv == -1) {
169             return statusFromErrno(errno, "shutdown() failed");
170         }
171         return status::ok;
172     }
173 
close(Fd fd) const174     Status close(Fd fd) const override {
175         auto rv = ::close(fd.get());
176         if (rv == -1) {
177             return statusFromErrno(errno, "close() failed");
178         }
179         return status::ok;
180     }
181 
fopen(const std::string & path,const std::string & mode) const182     StatusOr<UniqueFile> fopen(const std::string& path, const std::string& mode) const override {
183         UniqueFile file(::fopen(path.c_str(), mode.c_str()));
184         if (file == NULL) {
185             return statusFromErrno(errno, "fopen(\"" + path + "\", \"" + mode + "\") failed");
186         }
187         return file;
188     }
189 
fork() const190     StatusOr<pid_t> fork() const override {
191         pid_t rv = ::fork();
192         if (rv == -1) {
193             return statusFromErrno(errno, "fork() failed");
194         }
195         return rv;
196     }
197 
vfprintf(FILE * file,const char * format,va_list ap) const198     StatusOr<int> vfprintf(FILE* file, const char* format, va_list ap) const override {
199         auto rv = ::vfprintf(file, format, ap);
200         if (rv == -1) {
201             return statusFromErrno(errno, "vfprintf() failed");
202         }
203         return rv;
204     }
205 
vfscanf(FILE * file,const char * format,va_list ap) const206     StatusOr<int> vfscanf(FILE* file, const char* format, va_list ap) const override {
207         auto rv = ::vfscanf(file, format, ap);
208         if (rv == -1) {
209             return statusFromErrno(errno, "vfscanf() failed");
210         }
211         return rv;
212     }
213 
fclose(FILE * file) const214     Status fclose(FILE* file) const override {
215         auto rv = ::fclose(file);
216         if (rv == -1) {
217             return statusFromErrno(errno, "fclose() failed");
218         }
219         return status::ok;
220     }
221 };
222 
~SyscallsHolder()223 SyscallsHolder::~SyscallsHolder() {
224     delete &get();
225 }
226 
get()227 Syscalls& SyscallsHolder::get() {
228     while (true) {
229         // memory_order_relaxed gives the compiler and hardware more
230         // freedom. If we get a stale value (this should only happen
231         // early in the execution of a program) the exchange code below
232         // will loop until we get the most current value.
233         auto* syscalls = mSyscalls.load(std::memory_order_relaxed);
234         // Common case returns existing syscalls
235         if (syscalls) {
236             return *syscalls;
237         }
238 
239         // This code will execute on first get()
240         std::unique_ptr<Syscalls> tmp(new RealSyscalls());
241         Syscalls* expected = nullptr;
242         bool success = mSyscalls.compare_exchange_strong(expected, tmp.get());
243         if (success) {
244             // Ownership was transferred to mSyscalls already, must release()
245             return *tmp.release();
246         }
247     }
248 }
249 
swap(Syscalls & syscalls)250 Syscalls& SyscallsHolder::swap(Syscalls& syscalls) {
251     return *mSyscalls.exchange(&syscalls);
252 }
253 
254 SyscallsHolder sSyscalls;
255 
256 }  // namespace netdutils
257 }  // namespace android
258