client_channel.cpp revision fd22b3e5ad1aae1fc3de54801f33466db3c9b3fe
1#include "uds/client_channel.h"
2
3#include <errno.h>
4#include <log/log.h>
5#include <sys/epoll.h>
6#include <sys/socket.h>
7
8#include <pdx/client.h>
9#include <pdx/service_endpoint.h>
10#include <uds/ipc_helper.h>
11
12namespace android {
13namespace pdx {
14namespace uds {
15
16namespace {
17
18struct TransactionState {
19  bool GetLocalFileHandle(int index, LocalHandle* handle) {
20    if (index < 0) {
21      handle->Reset(index);
22    } else if (static_cast<size_t>(index) < response.file_descriptors.size()) {
23      *handle = std::move(response.file_descriptors[index]);
24    } else {
25      return false;
26    }
27    return true;
28  }
29
30  bool GetLocalChannelHandle(int index, LocalChannelHandle* handle) {
31    if (index < 0) {
32      *handle = LocalChannelHandle{nullptr, index};
33    } else if (static_cast<size_t>(index) < response.channels.size()) {
34      auto& channel_info = response.channels[index];
35      *handle = ChannelManager::Get().CreateHandle(
36          std::move(channel_info.data_fd), std::move(channel_info.event_fd));
37    } else {
38      return false;
39    }
40    return true;
41  }
42
43  FileReference PushFileHandle(BorrowedHandle handle) {
44    if (!handle)
45      return handle.Get();
46    request.file_descriptors.push_back(std::move(handle));
47    return request.file_descriptors.size() - 1;
48  }
49
50  ChannelReference PushChannelHandle(BorrowedChannelHandle handle) {
51    if (!handle)
52      return handle.value();
53
54    if (auto* channel_data =
55            ChannelManager::Get().GetChannelData(handle.value())) {
56      ChannelInfo<BorrowedHandle> channel_info;
57      channel_info.data_fd.Reset(handle.value());
58      channel_info.event_fd = channel_data->event_receiver.event_fd();
59      request.channels.push_back(std::move(channel_info));
60      return request.channels.size() - 1;
61    } else {
62      return -1;
63    }
64  }
65
66  RequestHeader<BorrowedHandle> request;
67  ResponseHeader<LocalHandle> response;
68};
69
70Status<void> ReadAndDiscardData(const BorrowedHandle& socket_fd, size_t size) {
71  while (size > 0) {
72    // If there is more data to read in the message than the buffers provided
73    // by the caller, read and discard the extra data from the socket.
74    char buffer[1024];
75    size_t size_to_read = std::min(sizeof(buffer), size);
76    auto status = ReceiveData(socket_fd, buffer, size_to_read);
77    if (!status)
78      return status;
79    size -= size_to_read;
80  }
81  // We still want to return EIO error to the caller in case we had unexpected
82  // data in the socket stream.
83  return ErrorStatus(EIO);
84}
85
86Status<void> SendRequest(const BorrowedHandle& socket_fd,
87                         TransactionState* transaction_state, int opcode,
88                         const iovec* send_vector, size_t send_count,
89                         size_t max_recv_len) {
90  size_t send_len = CountVectorSize(send_vector, send_count);
91  InitRequest(&transaction_state->request, opcode, send_len, max_recv_len,
92              false);
93  auto status = SendData(socket_fd, transaction_state->request);
94  if (status && send_len > 0)
95    status = SendDataVector(socket_fd, send_vector, send_count);
96  return status;
97}
98
99Status<void> ReceiveResponse(const BorrowedHandle& socket_fd,
100                             TransactionState* transaction_state,
101                             const iovec* receive_vector, size_t receive_count,
102                             size_t max_recv_len) {
103  auto status = ReceiveData(socket_fd, &transaction_state->response);
104  if (!status)
105    return status;
106
107  if (transaction_state->response.recv_len > 0) {
108    std::vector<iovec> read_buffers;
109    size_t size_remaining = 0;
110    if (transaction_state->response.recv_len != max_recv_len) {
111      // If the receive buffer not exactly the size of data available, recreate
112      // the vector list to consume the data exactly since ReceiveDataVector()
113      // validates that the number of bytes received equals the number of bytes
114      // requested.
115      size_remaining = transaction_state->response.recv_len;
116      for (size_t i = 0; i < receive_count && size_remaining > 0; i++) {
117        read_buffers.push_back(receive_vector[i]);
118        iovec& last_vec = read_buffers.back();
119        if (last_vec.iov_len > size_remaining)
120          last_vec.iov_len = size_remaining;
121        size_remaining -= last_vec.iov_len;
122      }
123      receive_vector = read_buffers.data();
124      receive_count = read_buffers.size();
125    }
126    status = ReceiveDataVector(socket_fd, receive_vector, receive_count);
127    if (status && size_remaining > 0)
128      status = ReadAndDiscardData(socket_fd, size_remaining);
129  }
130  return status;
131}
132
133}  // anonymous namespace
134
135ClientChannel::ClientChannel(LocalChannelHandle channel_handle)
136    : channel_handle_{std::move(channel_handle)} {
137  channel_data_ = ChannelManager::Get().GetChannelData(channel_handle_.value());
138}
139
140std::unique_ptr<pdx::ClientChannel> ClientChannel::Create(
141    LocalChannelHandle channel_handle) {
142  return std::unique_ptr<pdx::ClientChannel>{
143      new ClientChannel{std::move(channel_handle)}};
144}
145
146ClientChannel::~ClientChannel() {
147  if (channel_handle_)
148    shutdown(channel_handle_.value(), SHUT_WR);
149}
150
151void* ClientChannel::AllocateTransactionState() { return new TransactionState; }
152
153void ClientChannel::FreeTransactionState(void* state) {
154  delete static_cast<TransactionState*>(state);
155}
156
157Status<void> ClientChannel::SendImpulse(int opcode, const void* buffer,
158                                        size_t length) {
159  std::unique_lock<std::mutex> lock(socket_mutex_);
160  Status<void> status;
161  android::pdx::uds::RequestHeader<BorrowedHandle> request;
162  if (length > request.impulse_payload.size() ||
163      (buffer == nullptr && length != 0)) {
164    status.SetError(EINVAL);
165    return status;
166  }
167
168  InitRequest(&request, opcode, length, 0, true);
169  memcpy(request.impulse_payload.data(), buffer, length);
170  return SendData(BorrowedHandle{channel_handle_.value()}, request);
171}
172
173Status<int> ClientChannel::SendAndReceive(void* transaction_state, int opcode,
174                                          const iovec* send_vector,
175                                          size_t send_count,
176                                          const iovec* receive_vector,
177                                          size_t receive_count) {
178  std::unique_lock<std::mutex> lock(socket_mutex_);
179  Status<int> result;
180  if ((send_vector == nullptr && send_count != 0) ||
181      (receive_vector == nullptr && receive_count != 0)) {
182    result.SetError(EINVAL);
183    return result;
184  }
185
186  auto* state = static_cast<TransactionState*>(transaction_state);
187  size_t max_recv_len = CountVectorSize(receive_vector, receive_count);
188
189  auto status = SendRequest(BorrowedHandle{channel_handle_.value()}, state,
190                            opcode, send_vector, send_count, max_recv_len);
191  if (status) {
192    status = ReceiveResponse(BorrowedHandle{channel_handle_.value()}, state,
193                             receive_vector, receive_count, max_recv_len);
194  }
195  if (!result.PropagateError(status)) {
196    const int return_code = state->response.ret_code;
197    if (return_code >= 0)
198      result.SetValue(return_code);
199    else
200      result.SetError(-return_code);
201  }
202  return result;
203}
204
205Status<int> ClientChannel::SendWithInt(void* transaction_state, int opcode,
206                                       const iovec* send_vector,
207                                       size_t send_count,
208                                       const iovec* receive_vector,
209                                       size_t receive_count) {
210  return SendAndReceive(transaction_state, opcode, send_vector, send_count,
211                        receive_vector, receive_count);
212}
213
214Status<LocalHandle> ClientChannel::SendWithFileHandle(
215    void* transaction_state, int opcode, const iovec* send_vector,
216    size_t send_count, const iovec* receive_vector, size_t receive_count) {
217  Status<int> int_status =
218      SendAndReceive(transaction_state, opcode, send_vector, send_count,
219                     receive_vector, receive_count);
220  Status<LocalHandle> status;
221  if (status.PropagateError(int_status))
222    return status;
223
224  auto* state = static_cast<TransactionState*>(transaction_state);
225  LocalHandle handle;
226  if (state->GetLocalFileHandle(int_status.get(), &handle)) {
227    status.SetValue(std::move(handle));
228  } else {
229    status.SetError(EINVAL);
230  }
231  return status;
232}
233
234Status<LocalChannelHandle> ClientChannel::SendWithChannelHandle(
235    void* transaction_state, int opcode, const iovec* send_vector,
236    size_t send_count, const iovec* receive_vector, size_t receive_count) {
237  Status<int> int_status =
238      SendAndReceive(transaction_state, opcode, send_vector, send_count,
239                     receive_vector, receive_count);
240  Status<LocalChannelHandle> status;
241  if (status.PropagateError(int_status))
242    return status;
243
244  auto* state = static_cast<TransactionState*>(transaction_state);
245  LocalChannelHandle handle;
246  if (state->GetLocalChannelHandle(int_status.get(), &handle)) {
247    status.SetValue(std::move(handle));
248  } else {
249    status.SetError(EINVAL);
250  }
251  return status;
252}
253
254FileReference ClientChannel::PushFileHandle(void* transaction_state,
255                                            const LocalHandle& handle) {
256  auto* state = static_cast<TransactionState*>(transaction_state);
257  return state->PushFileHandle(handle.Borrow());
258}
259
260FileReference ClientChannel::PushFileHandle(void* transaction_state,
261                                            const BorrowedHandle& handle) {
262  auto* state = static_cast<TransactionState*>(transaction_state);
263  return state->PushFileHandle(handle.Duplicate());
264}
265
266ChannelReference ClientChannel::PushChannelHandle(
267    void* transaction_state, const LocalChannelHandle& handle) {
268  auto* state = static_cast<TransactionState*>(transaction_state);
269  return state->PushChannelHandle(handle.Borrow());
270}
271
272ChannelReference ClientChannel::PushChannelHandle(
273    void* transaction_state, const BorrowedChannelHandle& handle) {
274  auto* state = static_cast<TransactionState*>(transaction_state);
275  return state->PushChannelHandle(handle.Duplicate());
276}
277
278bool ClientChannel::GetFileHandle(void* transaction_state, FileReference ref,
279                                  LocalHandle* handle) const {
280  auto* state = static_cast<TransactionState*>(transaction_state);
281  return state->GetLocalFileHandle(ref, handle);
282}
283
284bool ClientChannel::GetChannelHandle(void* transaction_state,
285                                     ChannelReference ref,
286                                     LocalChannelHandle* handle) const {
287  auto* state = static_cast<TransactionState*>(transaction_state);
288  return state->GetLocalChannelHandle(ref, handle);
289}
290
291}  // namespace uds
292}  // namespace pdx
293}  // namespace android
294