ipc_helper.h revision 52ea25cf06cef250ec73052611b48556b3fce4d5
1#ifndef ANDROID_PDX_UDS_IPC_HELPER_H_
2#define ANDROID_PDX_UDS_IPC_HELPER_H_
3
4#include <sys/socket.h>
5#include <utility>
6#include <vector>
7
8#include <pdx/rpc/serializable.h>
9#include <pdx/rpc/serialization.h>
10#include <pdx/status.h>
11#include <pdx/utility.h>
12
13namespace android {
14namespace pdx {
15namespace uds {
16
17// Test interfaces used for unit-testing payload sending/receiving over sockets.
18class SendInterface {
19 public:
20  virtual ssize_t Send(int socket_fd, const void* data, size_t size,
21                       int flags) = 0;
22  virtual ssize_t SendMessage(int socket_fd, const msghdr* msg, int flags) = 0;
23
24 protected:
25  virtual ~SendInterface() = default;
26};
27
28class RecvInterface {
29 public:
30  virtual ssize_t Receive(int socket_fd, void* data, size_t size,
31                          int flags) = 0;
32  virtual ssize_t ReceiveMessage(int socket_fd, msghdr* msg, int flags) = 0;
33
34 protected:
35  virtual ~RecvInterface() = default;
36};
37
38// Helper methods that allow to send/receive data through abstract interfaces.
39// Useful for mocking out the underlying socket I/O.
40Status<void> SendAll(SendInterface* sender, const BorrowedHandle& socket_fd,
41                     const void* data, size_t size);
42Status<void> SendMsgAll(SendInterface* sender, const BorrowedHandle& socket_fd,
43                        const msghdr* msg);
44Status<void> RecvAll(RecvInterface* receiver, const BorrowedHandle& socket_fd,
45                     void* data, size_t size);
46Status<void> RecvMsgAll(RecvInterface* receiver,
47                        const BorrowedHandle& socket_fd, msghdr* msg);
48
49#define RETRY_EINTR(fnc_call)                 \
50  ([&]() -> decltype(fnc_call) {              \
51    decltype(fnc_call) result;                \
52    do {                                      \
53      result = (fnc_call);                    \
54    } while (result == -1 && errno == EINTR); \
55    return result;                            \
56  })()
57
58class SendPayload : public MessageWriter, public OutputResourceMapper {
59 public:
60  SendPayload(SendInterface* sender = nullptr) : sender_{sender} {}
61  Status<void> Send(const BorrowedHandle& socket_fd);
62  Status<void> Send(const BorrowedHandle& socket_fd, const ucred* cred,
63                    const iovec* data_vec = nullptr, size_t vec_count = 0);
64
65  // MessageWriter
66  void* GetNextWriteBufferSection(size_t size) override;
67  OutputResourceMapper* GetOutputResourceMapper() override;
68
69  // OutputResourceMapper
70  Status<FileReference> PushFileHandle(const LocalHandle& handle) override;
71  Status<FileReference> PushFileHandle(const BorrowedHandle& handle) override;
72  Status<FileReference> PushFileHandle(const RemoteHandle& handle) override;
73  Status<ChannelReference> PushChannelHandle(
74      const LocalChannelHandle& handle) override;
75  Status<ChannelReference> PushChannelHandle(
76      const BorrowedChannelHandle& handle) override;
77  Status<ChannelReference> PushChannelHandle(
78      const RemoteChannelHandle& handle) override;
79
80 private:
81  SendInterface* sender_;
82  ByteBuffer buffer_;
83  std::vector<int> file_handles_;
84};
85
86class ReceivePayload : public MessageReader, public InputResourceMapper {
87 public:
88  ReceivePayload(RecvInterface* receiver = nullptr) : receiver_{receiver} {}
89  Status<void> Receive(const BorrowedHandle& socket_fd);
90  Status<void> Receive(const BorrowedHandle& socket_fd, ucred* cred);
91
92  // MessageReader
93  BufferSection GetNextReadBufferSection() override;
94  void ConsumeReadBufferSectionData(const void* new_start) override;
95  InputResourceMapper* GetInputResourceMapper() override;
96
97  // InputResourceMapper
98  bool GetFileHandle(FileReference ref, LocalHandle* handle) override;
99  bool GetChannelHandle(ChannelReference ref,
100                        LocalChannelHandle* handle) override;
101
102 private:
103  RecvInterface* receiver_;
104  ByteBuffer buffer_;
105  std::vector<LocalHandle> file_handles_;
106  size_t read_pos_{0};
107};
108
109template <typename FileHandleType>
110class ChannelInfo {
111 public:
112  FileHandleType data_fd;
113  FileHandleType pollin_event_fd;
114  FileHandleType pollhup_event_fd;
115
116 private:
117  PDX_SERIALIZABLE_MEMBERS(ChannelInfo, data_fd, pollin_event_fd,
118                           pollhup_event_fd);
119};
120
121template <typename FileHandleType>
122class ChannelConnectionInfo {
123 public:
124  FileHandleType channel_fd;
125
126 private:
127  PDX_SERIALIZABLE_MEMBERS(ChannelConnectionInfo, channel_fd);
128};
129
130template <typename FileHandleType>
131class RequestHeader {
132 public:
133  int32_t op{0};
134  ucred cred;
135  uint32_t send_len{0};
136  uint32_t max_recv_len{0};
137  std::vector<FileHandleType> file_descriptors;
138  std::vector<ChannelInfo<FileHandleType>> channels;
139  std::array<uint8_t, 32> impulse_payload;
140  bool is_impulse{false};
141
142 private:
143  PDX_SERIALIZABLE_MEMBERS(RequestHeader, op, send_len, max_recv_len,
144                           file_descriptors, channels, impulse_payload,
145                           is_impulse);
146};
147
148template <typename FileHandleType>
149class ResponseHeader {
150 public:
151  int32_t ret_code{0};
152  uint32_t recv_len{0};
153  std::vector<FileHandleType> file_descriptors;
154  std::vector<ChannelInfo<FileHandleType>> channels;
155
156 private:
157  PDX_SERIALIZABLE_MEMBERS(ResponseHeader, ret_code, recv_len, file_descriptors,
158                           channels);
159};
160
161template <typename T>
162inline Status<void> SendData(const BorrowedHandle& socket_fd, const T& data,
163                             const iovec* data_vec = nullptr,
164                             size_t vec_count = 0) {
165  SendPayload payload;
166  rpc::Serialize(data, &payload);
167  return payload.Send(socket_fd, nullptr, data_vec, vec_count);
168}
169
170template <typename FileHandleType>
171inline Status<void> SendData(const BorrowedHandle& socket_fd,
172                             const RequestHeader<FileHandleType>& request,
173                             const iovec* data_vec = nullptr,
174                             size_t vec_count = 0) {
175  SendPayload payload;
176  rpc::Serialize(request, &payload);
177  return payload.Send(socket_fd, &request.cred, data_vec, vec_count);
178}
179
180Status<void> SendData(const BorrowedHandle& socket_fd, const void* data,
181                      size_t size);
182Status<void> SendDataVector(const BorrowedHandle& socket_fd, const iovec* data,
183                            size_t count);
184
185template <typename T>
186inline Status<void> ReceiveData(const BorrowedHandle& socket_fd, T* data) {
187  ReceivePayload payload;
188  Status<void> status = payload.Receive(socket_fd);
189  if (status && rpc::Deserialize(data, &payload) != rpc::ErrorCode::NO_ERROR)
190    status.SetError(EIO);
191  return status;
192}
193
194template <typename FileHandleType>
195inline Status<void> ReceiveData(const BorrowedHandle& socket_fd,
196                                RequestHeader<FileHandleType>* request) {
197  ReceivePayload payload;
198  Status<void> status = payload.Receive(socket_fd, &request->cred);
199  if (status && rpc::Deserialize(request, &payload) != rpc::ErrorCode::NO_ERROR)
200    status.SetError(EIO);
201  return status;
202}
203
204Status<void> ReceiveData(const BorrowedHandle& socket_fd, void* data,
205                         size_t size);
206Status<void> ReceiveDataVector(const BorrowedHandle& socket_fd,
207                               const iovec* data, size_t count);
208
209size_t CountVectorSize(const iovec* data, size_t count);
210void InitRequest(android::pdx::uds::RequestHeader<BorrowedHandle>* request,
211                 int opcode, uint32_t send_len, uint32_t max_recv_len,
212                 bool is_impulse);
213
214Status<void> WaitForEndpoint(const std::string& endpoint_path,
215                             int64_t timeout_ms);
216
217}  // namespace uds
218}  // namespace pdx
219}  // namespace android
220
221#endif  // ANDROID_PDX_UDS_IPC_HELPER_H_
222