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 #ifndef NETDUTILS_SYSCALLS_H
18 #define NETDUTILS_SYSCALLS_H
19 
20 #include <memory>
21 
22 #include <net/if.h>
23 #include <poll.h>
24 #include <sys/eventfd.h>
25 #include <sys/socket.h>
26 #include <sys/types.h>
27 #include <sys/uio.h>
28 #include <unistd.h>
29 
30 #include "netdutils/Fd.h"
31 #include "netdutils/Slice.h"
32 #include "netdutils/Socket.h"
33 #include "netdutils/Status.h"
34 #include "netdutils/StatusOr.h"
35 #include "netdutils/UniqueFd.h"
36 #include "netdutils/UniqueFile.h"
37 
38 namespace android {
39 namespace netdutils {
40 
41 class Syscalls {
42   public:
43     virtual ~Syscalls() = default;
44 
45     virtual StatusOr<UniqueFd> open(const std::string& pathname, int flags,
46                                     mode_t mode = 0) const = 0;
47 
48     virtual StatusOr<UniqueFd> socket(int domain, int type, int protocol) const = 0;
49 
50     virtual Status getsockname(Fd sock, sockaddr* addr, socklen_t* addrlen) const = 0;
51 
52     virtual Status getsockopt(Fd sock, int level, int optname, void *optval,
53                               socklen_t *optlen) const = 0;
54 
55     virtual Status setsockopt(Fd sock, int level, int optname, const void* optval,
56                               socklen_t optlen) const = 0;
57 
58     virtual Status bind(Fd sock, const sockaddr* addr, socklen_t addrlen) const = 0;
59 
60     virtual Status connect(Fd sock, const sockaddr* addr, socklen_t addrlen) const = 0;
61 
62     virtual StatusOr<ifreq> ioctl(Fd sock, unsigned long request, ifreq* ifr) const = 0;
63 
64     virtual StatusOr<UniqueFd> eventfd(unsigned int initval, int flags) const = 0;
65 
66     virtual StatusOr<int> ppoll(pollfd* fds, nfds_t nfds, double timeout) const = 0;
67 
68     virtual StatusOr<size_t> writev(Fd fd, const std::vector<iovec>& iov) const = 0;
69 
70     virtual StatusOr<size_t> write(Fd fd, const Slice buf) const = 0;
71 
72     virtual StatusOr<Slice> read(Fd fd, const Slice buf) const = 0;
73 
74     virtual StatusOr<size_t> sendto(Fd sock, const Slice buf, int flags, const sockaddr* dst,
75                                     socklen_t dstlen) const = 0;
76 
77     virtual StatusOr<Slice> recvfrom(Fd sock, const Slice dst, int flags, sockaddr* src,
78                                      socklen_t* srclen) const = 0;
79 
80     virtual Status shutdown(Fd fd, int how) const = 0;
81 
82     virtual Status close(Fd fd) const = 0;
83 
84     virtual StatusOr<UniqueFile> fopen(const std::string& path, const std::string& mode) const = 0;
85 
86     virtual StatusOr<int> vfprintf(FILE* file, const char* format, va_list ap) const = 0;
87 
88     virtual StatusOr<int> vfscanf(FILE* file, const char* format, va_list ap) const = 0;
89 
90     virtual Status fclose(FILE* file) const = 0;
91 
92     virtual StatusOr<pid_t> fork() const = 0;
93 
94     // va_args helpers
95     // va_start doesn't work when the preceding argument is a reference
96     // type so we're forced to use const char*.
fprintf(FILE * file,const char * format,...)97     StatusOr<int> fprintf(FILE* file, const char* format, ...) const {
98         va_list ap;
99         va_start(ap, format);
100         auto result = vfprintf(file, format, ap);
101         va_end(ap);
102         return result;
103     }
104 
105     // va_start doesn't work when the preceding argument is a reference
106     // type so we're forced to use const char*.
fscanf(FILE * file,const char * format,...)107     StatusOr<int> fscanf(FILE* file, const char* format, ...) const {
108         va_list ap;
109         va_start(ap, format);
110         auto result = vfscanf(file, format, ap);
111         va_end(ap);
112         return result;
113     }
114 
115     // Templated helpers that forward directly to methods declared above
116     template <typename SockaddrT>
getsockname(Fd sock)117     StatusOr<SockaddrT> getsockname(Fd sock) const {
118         SockaddrT addr = {};
119         socklen_t addrlen = sizeof(addr);
120         RETURN_IF_NOT_OK(getsockname(sock, asSockaddrPtr(&addr), &addrlen));
121         return addr;
122     }
123 
124     template <typename SockoptT>
getsockopt(Fd sock,int level,int optname,void * optval,socklen_t * optlen)125     Status getsockopt(Fd sock, int level, int optname, void* optval, socklen_t* optlen) const {
126         return getsockopt(sock, level, optname, optval, optlen);
127     }
128 
129     template <typename SockoptT>
setsockopt(Fd sock,int level,int optname,const SockoptT & opt)130     Status setsockopt(Fd sock, int level, int optname, const SockoptT& opt) const {
131         return setsockopt(sock, level, optname, &opt, sizeof(opt));
132     }
133 
134     template <typename SockaddrT>
bind(Fd sock,const SockaddrT & addr)135     Status bind(Fd sock, const SockaddrT& addr) const {
136         return bind(sock, asSockaddrPtr(&addr), sizeof(addr));
137     }
138 
139     template <typename SockaddrT>
connect(Fd sock,const SockaddrT & addr)140     Status connect(Fd sock, const SockaddrT& addr) const {
141         return connect(sock, asSockaddrPtr(&addr), sizeof(addr));
142     }
143 
144     template <size_t size>
ppoll(const std::array<Fd,size> & fds,uint16_t events,double timeout)145     StatusOr<std::array<uint16_t, size>> ppoll(const std::array<Fd, size>& fds, uint16_t events,
146                                                double timeout) const {
147         std::array<pollfd, size> tmp;
148         for (size_t i = 0; i < size; ++i) {
149             tmp[i].fd = fds[i].get();
150             tmp[i].events = events;
151             tmp[i].revents = 0;
152         }
153         RETURN_IF_NOT_OK(ppoll(tmp.data(), tmp.size(), timeout).status());
154         std::array<uint16_t, size> out;
155         for (size_t i = 0; i < size; ++i) {
156             out[i] = tmp[i].revents;
157         }
158         return out;
159     }
160 
161     template <typename SockaddrT>
sendto(Fd sock,const Slice buf,int flags,const SockaddrT & dst)162     StatusOr<size_t> sendto(Fd sock, const Slice buf, int flags, const SockaddrT& dst) const {
163         return sendto(sock, buf, flags, asSockaddrPtr(&dst), sizeof(dst));
164     }
165 
166     // Ignore src sockaddr
recvfrom(Fd sock,const Slice dst,int flags)167     StatusOr<Slice> recvfrom(Fd sock, const Slice dst, int flags) const {
168         return recvfrom(sock, dst, flags, nullptr, nullptr);
169     }
170 
171     template <typename SockaddrT>
recvfrom(Fd sock,const Slice dst,int flags)172     StatusOr<std::pair<Slice, SockaddrT>> recvfrom(Fd sock, const Slice dst, int flags) const {
173         SockaddrT addr = {};
174         socklen_t addrlen = sizeof(addr);
175         ASSIGN_OR_RETURN(auto used, recvfrom(sock, dst, flags, asSockaddrPtr(&addr), &addrlen));
176         return std::make_pair(used, addr);
177     }
178 };
179 
180 // Specialized singleton that supports zero initialization and runtime
181 // override of contained pointer.
182 class SyscallsHolder {
183   public:
184     ~SyscallsHolder();
185 
186     // Return a pointer to an unowned instance of Syscalls.
187     Syscalls& get();
188 
189     // Testing only: set the value returned by getSyscalls. Return the old value.
190     // Callers are responsible for restoring the previous value returned
191     // by getSyscalls to avoid leaks.
192     Syscalls& swap(Syscalls& syscalls);
193 
194   private:
195     std::atomic<Syscalls*> mSyscalls{nullptr};
196 };
197 
198 // Syscalls instance used throughout netdutils
199 extern SyscallsHolder sSyscalls;
200 
201 }  // namespace netdutils
202 }  // namespace android
203 
204 #endif /* NETDUTILS_SYSCALLS_H */
205