summaryrefslogtreecommitdiff
path: root/libnetdutils/include/netdutils/Syscalls.h
blob: 36fcd853289cab13d07f86860be143e51f3aeee8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef NETDUTILS_SYSCALLS_H
#define NETDUTILS_SYSCALLS_H

#include <memory>

#include <net/if.h>
#include <poll.h>
#include <sys/eventfd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>

#include "netdutils/Fd.h"
#include "netdutils/Slice.h"
#include "netdutils/Socket.h"
#include "netdutils/Status.h"
#include "netdutils/StatusOr.h"
#include "netdutils/UniqueFd.h"
#include "netdutils/UniqueFile.h"

namespace android {
namespace netdutils {

class Syscalls {
  public:
    virtual ~Syscalls() = default;

    virtual StatusOr<UniqueFd> open(const std::string& pathname, int flags,
                                    mode_t mode = 0) const = 0;

    virtual StatusOr<UniqueFd> socket(int domain, int type, int protocol) const = 0;

    virtual Status getsockname(Fd sock, sockaddr* addr, socklen_t* addrlen) const = 0;

    virtual Status getsockopt(Fd sock, int level, int optname, void *optval,
                              socklen_t *optlen) const = 0;

    virtual Status setsockopt(Fd sock, int level, int optname, const void* optval,
                              socklen_t optlen) const = 0;

    virtual Status bind(Fd sock, const sockaddr* addr, socklen_t addrlen) const = 0;

    virtual Status connect(Fd sock, const sockaddr* addr, socklen_t addrlen) const = 0;

    virtual StatusOr<ifreq> ioctl(Fd sock, unsigned long request, ifreq* ifr) const = 0;

    virtual StatusOr<UniqueFd> eventfd(unsigned int initval, int flags) const = 0;

    virtual StatusOr<int> ppoll(pollfd* fds, nfds_t nfds, double timeout) const = 0;

    virtual StatusOr<size_t> writev(Fd fd, const std::vector<iovec>& iov) const = 0;

    virtual StatusOr<size_t> write(Fd fd, const Slice buf) const = 0;

    virtual StatusOr<Slice> read(Fd fd, const Slice buf) const = 0;

    virtual StatusOr<size_t> sendto(Fd sock, const Slice buf, int flags, const sockaddr* dst,
                                    socklen_t dstlen) const = 0;

    virtual StatusOr<Slice> recvfrom(Fd sock, const Slice dst, int flags, sockaddr* src,
                                     socklen_t* srclen) const = 0;

    virtual Status shutdown(Fd fd, int how) const = 0;

    virtual Status close(Fd fd) const = 0;

    virtual StatusOr<UniqueFile> fopen(const std::string& path, const std::string& mode) const = 0;

    virtual StatusOr<int> vfprintf(FILE* file, const char* format, va_list ap) const = 0;

    virtual StatusOr<int> vfscanf(FILE* file, const char* format, va_list ap) const = 0;

    virtual Status fclose(FILE* file) const = 0;

    virtual StatusOr<pid_t> fork() const = 0;

    // va_args helpers
    // va_start doesn't work when the preceding argument is a reference
    // type so we're forced to use const char*.
    StatusOr<int> fprintf(FILE* file, const char* format, ...) const {
        va_list ap;
        va_start(ap, format);
        auto result = vfprintf(file, format, ap);
        va_end(ap);
        return result;
    }

    // va_start doesn't work when the preceding argument is a reference
    // type so we're forced to use const char*.
    StatusOr<int> fscanf(FILE* file, const char* format, ...) const {
        va_list ap;
        va_start(ap, format);
        auto result = vfscanf(file, format, ap);
        va_end(ap);
        return result;
    }

    // Templated helpers that forward directly to methods declared above
    template <typename SockaddrT>
    StatusOr<SockaddrT> getsockname(Fd sock) const {
        SockaddrT addr = {};
        socklen_t addrlen = sizeof(addr);
        RETURN_IF_NOT_OK(getsockname(sock, asSockaddrPtr(&addr), &addrlen));
        return addr;
    }

    template <typename SockoptT>
    Status getsockopt(Fd sock, int level, int optname, void* optval, socklen_t* optlen) const {
        return getsockopt(sock, level, optname, optval, optlen);
    }

    template <typename SockoptT>
    Status setsockopt(Fd sock, int level, int optname, const SockoptT& opt) const {
        return setsockopt(sock, level, optname, &opt, sizeof(opt));
    }

    template <typename SockaddrT>
    Status bind(Fd sock, const SockaddrT& addr) const {
        return bind(sock, asSockaddrPtr(&addr), sizeof(addr));
    }

    template <typename SockaddrT>
    Status connect(Fd sock, const SockaddrT& addr) const {
        return connect(sock, asSockaddrPtr(&addr), sizeof(addr));
    }

    template <size_t size>
    StatusOr<std::array<uint16_t, size>> ppoll(const std::array<Fd, size>& fds, uint16_t events,
                                               double timeout) const {
        std::array<pollfd, size> tmp;
        for (size_t i = 0; i < size; ++i) {
            tmp[i].fd = fds[i].get();
            tmp[i].events = events;
            tmp[i].revents = 0;
        }
        RETURN_IF_NOT_OK(ppoll(tmp.data(), tmp.size(), timeout).status());
        std::array<uint16_t, size> out;
        for (size_t i = 0; i < size; ++i) {
            out[i] = tmp[i].revents;
        }
        return out;
    }

    template <typename SockaddrT>
    StatusOr<size_t> sendto(Fd sock, const Slice buf, int flags, const SockaddrT& dst) const {
        return sendto(sock, buf, flags, asSockaddrPtr(&dst), sizeof(dst));
    }

    // Ignore src sockaddr
    StatusOr<Slice> recvfrom(Fd sock, const Slice dst, int flags) const {
        return recvfrom(sock, dst, flags, nullptr, nullptr);
    }

    template <typename SockaddrT>
    StatusOr<std::pair<Slice, SockaddrT>> recvfrom(Fd sock, const Slice dst, int flags) const {
        SockaddrT addr = {};
        socklen_t addrlen = sizeof(addr);
        ASSIGN_OR_RETURN(auto used, recvfrom(sock, dst, flags, asSockaddrPtr(&addr), &addrlen));
        return std::make_pair(used, addr);
    }
};

// Specialized singleton that supports zero initialization and runtime
// override of contained pointer.
class SyscallsHolder {
  public:
    ~SyscallsHolder();

    // Return a pointer to an unowned instance of Syscalls.
    Syscalls& get();

    // Testing only: set the value returned by getSyscalls. Return the old value.
    // Callers are responsible for restoring the previous value returned
    // by getSyscalls to avoid leaks.
    Syscalls& swap(Syscalls& syscalls);

  private:
    std::atomic<Syscalls*> mSyscalls{nullptr};
};

// Syscalls instance used throughout netdutils
extern SyscallsHolder sSyscalls;

}  // namespace netdutils
}  // namespace android

#endif /* NETDUTILS_SYSCALLS_H */