blob: 3b2c8264531b680ba4b40de09319d07314441b81 [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
44 StatusOr<UniqueFd> socket(int domain, int type, int protocol) const override {
45 UniqueFd sock(::socket(domain, type, protocol));
46 if (!isWellFormed(sock)) {
47 return statusFromErrno(errno, "socket() failed");
48 }
49 return sock;
50 }
51
52 Status getsockname(Fd sock, sockaddr* addr, socklen_t* addrlen) const override {
53 auto rv = ::getsockname(sock.get(), addr, addrlen);
54 if (rv == -1) {
55 return statusFromErrno(errno, "getsockname() failed");
56 }
57 return status::ok;
58 }
59
60 Status setsockopt(Fd sock, int level, int optname, const void* optval,
61 socklen_t optlen) const override {
62 auto rv = ::setsockopt(sock.get(), level, optname, optval, optlen);
63 if (rv == -1) {
64 return statusFromErrno(errno, "setsockopt() failed");
65 }
66 return status::ok;
67 }
68
69 Status bind(Fd sock, const sockaddr* addr, socklen_t addrlen) const override {
70 auto rv = ::bind(sock.get(), addr, addrlen);
71 if (rv == -1) {
72 return statusFromErrno(errno, "bind() failed");
73 }
74 return status::ok;
75 }
76
77 Status connect(Fd sock, const sockaddr* addr, socklen_t addrlen) const override {
78 auto rv = syscallRetry(::connect, sock.get(), addr, addrlen);
79 if (rv == -1) {
80 return statusFromErrno(errno, "connect() failed");
81 }
82 return status::ok;
83 }
84
85 StatusOr<UniqueFd> eventfd(unsigned int initval, int flags) const override {
86 UniqueFd fd(::eventfd(initval, flags));
87 if (!isWellFormed(fd)) {
88 return statusFromErrno(errno, "eventfd() failed");
89 }
90 return fd;
91 }
92
93 StatusOr<int> ppoll(pollfd* fds, nfds_t nfds, double timeout) const override {
94 timespec ts = {};
95 ts.tv_sec = timeout;
96 ts.tv_nsec = (timeout - ts.tv_sec) * 1e9;
97 auto rv = syscallRetry(::ppoll, fds, nfds, &ts, nullptr);
98 if (rv == -1) {
99 return statusFromErrno(errno, "ppoll() failed");
100 }
101 return rv;
102 }
103
104 StatusOr<size_t> write(Fd fd, const Slice buf) const override {
105 auto rv = syscallRetry(::write, fd.get(), buf.base(), buf.size());
106 if (rv == -1) {
107 return statusFromErrno(errno, "write() failed");
108 }
109 return static_cast<size_t>(rv);
110 }
111
112 StatusOr<Slice> read(Fd fd, const Slice buf) const override {
113 auto rv = syscallRetry(::read, fd.get(), buf.base(), buf.size());
114 if (rv == -1) {
115 return statusFromErrno(errno, "read() failed");
116 }
117 return Slice(buf.base(), rv);
118 }
119
120 StatusOr<size_t> sendto(Fd sock, const Slice buf, int flags, const sockaddr* dst,
121 socklen_t dstlen) const override {
122 auto rv = syscallRetry(::sendto, sock.get(), buf.base(), buf.size(), flags, dst, dstlen);
123 if (rv == -1) {
124 return statusFromErrno(errno, "sendto() failed");
125 }
126 return static_cast<size_t>(rv);
127 }
128
129 StatusOr<Slice> recvfrom(Fd sock, const Slice dst, int flags, sockaddr* src,
130 socklen_t* srclen) const override {
131 auto rv = syscallRetry(::recvfrom, sock.get(), dst.base(), dst.size(), flags, src, srclen);
132 if (rv == -1) {
133 return statusFromErrno(errno, "recvfrom() failed");
134 }
135 if (rv == 0) {
136 return status::eof;
137 }
138 return take(dst, rv);
139 }
140
141 Status shutdown(Fd fd, int how) const override {
142 auto rv = ::shutdown(fd.get(), how);
143 if (rv == -1) {
144 return statusFromErrno(errno, "shutdown() failed");
145 }
146 return status::ok;
147 }
148
149 Status close(Fd fd) const override {
150 auto rv = ::close(fd.get());
151 if (rv == -1) {
152 return statusFromErrno(errno, "close)( failed");
153 }
154 return status::ok;
155 }
156};
157
158SyscallsHolder::~SyscallsHolder() {
159 delete &get();
160}
161
162Syscalls& SyscallsHolder::get() {
163 while (true) {
164 // memory_order_relaxed gives the compiler and hardware more
165 // freedom. If we get a stale value (this should only happen
166 // early in the execution of a program) the exchange code below
167 // will loop until we get the most current value.
168 auto* syscalls = mSyscalls.load(std::memory_order_relaxed);
169 // Common case returns existing syscalls
170 if (syscalls) {
171 return *syscalls;
172 }
173
174 // This code will execute on first get()
175 std::unique_ptr<Syscalls> tmp(new RealSyscalls());
176 Syscalls* expected = nullptr;
177 bool success = mSyscalls.compare_exchange_strong(expected, tmp.get());
178 if (success) {
179 // Ownership was transferred to mSyscalls already, must release()
180 return *tmp.release();
181 }
182 }
183}
184
185Syscalls& SyscallsHolder::swap(Syscalls& syscalls) {
186 return *mSyscalls.exchange(&syscalls);
187}
188
189SyscallsHolder sSyscalls;
190
191} // namespace netdutils
192} // namespace android