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