#include "uds/channel_parcelable.h" #include "uds/client_channel.h" #include #include #include #include #include #include #include namespace android { namespace pdx { namespace uds { namespace { struct TransactionState { bool GetLocalFileHandle(int index, LocalHandle* handle) { if (index < 0) { handle->Reset(index); } else if (static_cast(index) < response.file_descriptors.size()) { *handle = std::move(response.file_descriptors[index]); } else { return false; } return true; } bool GetLocalChannelHandle(int index, LocalChannelHandle* handle) { if (index < 0) { *handle = LocalChannelHandle{nullptr, index}; } else if (static_cast(index) < response.channels.size()) { auto& channel_info = response.channels[index]; *handle = ChannelManager::Get().CreateHandle( std::move(channel_info.data_fd), std::move(channel_info.pollin_event_fd), std::move(channel_info.pollhup_event_fd)); } else { return false; } return true; } FileReference PushFileHandle(BorrowedHandle handle) { if (!handle) return handle.Get(); request.file_descriptors.push_back(std::move(handle)); return request.file_descriptors.size() - 1; } ChannelReference PushChannelHandle(BorrowedChannelHandle handle) { if (!handle) return handle.value(); if (auto* channel_data = ChannelManager::Get().GetChannelData(handle.value())) { ChannelInfo channel_info{ channel_data->data_fd(), channel_data->pollin_event_fd(), channel_data->pollhup_event_fd()}; request.channels.push_back(std::move(channel_info)); return request.channels.size() - 1; } else { return -1; } } RequestHeader request; ResponseHeader response; }; Status ReadAndDiscardData(const BorrowedHandle& socket_fd, size_t size) { while (size > 0) { // If there is more data to read in the message than the buffers provided // by the caller, read and discard the extra data from the socket. char buffer[1024]; size_t size_to_read = std::min(sizeof(buffer), size); auto status = ReceiveData(socket_fd, buffer, size_to_read); if (!status) return status; size -= size_to_read; } // We still want to return EIO error to the caller in case we had unexpected // data in the socket stream. return ErrorStatus(EIO); } Status SendRequest(const BorrowedHandle& socket_fd, TransactionState* transaction_state, int opcode, const iovec* send_vector, size_t send_count, size_t max_recv_len) { size_t send_len = CountVectorSize(send_vector, send_count); InitRequest(&transaction_state->request, opcode, send_len, max_recv_len, false); if (send_len == 0) { send_vector = nullptr; send_count = 0; } return SendData(socket_fd, transaction_state->request, send_vector, send_count); } Status ReceiveResponse(const BorrowedHandle& socket_fd, TransactionState* transaction_state, const iovec* receive_vector, size_t receive_count, size_t max_recv_len) { auto status = ReceiveData(socket_fd, &transaction_state->response); if (!status) return status; if (transaction_state->response.recv_len > 0) { std::vector read_buffers; size_t size_remaining = 0; if (transaction_state->response.recv_len != max_recv_len) { // If the receive buffer not exactly the size of data available, recreate // the vector list to consume the data exactly since ReceiveDataVector() // validates that the number of bytes received equals the number of bytes // requested. size_remaining = transaction_state->response.recv_len; for (size_t i = 0; i < receive_count && size_remaining > 0; i++) { read_buffers.push_back(receive_vector[i]); iovec& last_vec = read_buffers.back(); if (last_vec.iov_len > size_remaining) last_vec.iov_len = size_remaining; size_remaining -= last_vec.iov_len; } receive_vector = read_buffers.data(); receive_count = read_buffers.size(); } status = ReceiveDataVector(socket_fd, receive_vector, receive_count); if (status && size_remaining > 0) status = ReadAndDiscardData(socket_fd, size_remaining); } return status; } } // anonymous namespace ClientChannel::ClientChannel(LocalChannelHandle channel_handle) : channel_handle_{std::move(channel_handle)} { channel_data_ = ChannelManager::Get().GetChannelData(channel_handle_.value()); } std::unique_ptr ClientChannel::Create( LocalChannelHandle channel_handle) { return std::unique_ptr{ new ClientChannel{std::move(channel_handle)}}; } ClientChannel::~ClientChannel() { if (channel_handle_) shutdown(channel_handle_.value(), SHUT_WR); } void* ClientChannel::AllocateTransactionState() { return new TransactionState; } void ClientChannel::FreeTransactionState(void* state) { delete static_cast(state); } Status ClientChannel::SendImpulse(int opcode, const void* buffer, size_t length) { std::unique_lock lock(socket_mutex_); Status status; android::pdx::uds::RequestHeader request; if (length > request.impulse_payload.size() || (buffer == nullptr && length != 0)) { status.SetError(EINVAL); return status; } InitRequest(&request, opcode, length, 0, true); memcpy(request.impulse_payload.data(), buffer, length); return SendData(BorrowedHandle{channel_handle_.value()}, request); } Status ClientChannel::SendAndReceive(void* transaction_state, int opcode, const iovec* send_vector, size_t send_count, const iovec* receive_vector, size_t receive_count) { std::unique_lock lock(socket_mutex_); Status result; if ((send_vector == nullptr && send_count != 0) || (receive_vector == nullptr && receive_count != 0)) { result.SetError(EINVAL); return result; } auto* state = static_cast(transaction_state); size_t max_recv_len = CountVectorSize(receive_vector, receive_count); auto status = SendRequest(BorrowedHandle{channel_handle_.value()}, state, opcode, send_vector, send_count, max_recv_len); if (status) { status = ReceiveResponse(BorrowedHandle{channel_handle_.value()}, state, receive_vector, receive_count, max_recv_len); } if (!result.PropagateError(status)) { const int return_code = state->response.ret_code; if (return_code >= 0) result.SetValue(return_code); else result.SetError(-return_code); } return result; } Status ClientChannel::SendWithInt(void* transaction_state, int opcode, const iovec* send_vector, size_t send_count, const iovec* receive_vector, size_t receive_count) { return SendAndReceive(transaction_state, opcode, send_vector, send_count, receive_vector, receive_count); } Status ClientChannel::SendWithFileHandle( void* transaction_state, int opcode, const iovec* send_vector, size_t send_count, const iovec* receive_vector, size_t receive_count) { Status int_status = SendAndReceive(transaction_state, opcode, send_vector, send_count, receive_vector, receive_count); Status status; if (status.PropagateError(int_status)) return status; auto* state = static_cast(transaction_state); LocalHandle handle; if (state->GetLocalFileHandle(int_status.get(), &handle)) { status.SetValue(std::move(handle)); } else { status.SetError(EINVAL); } return status; } Status ClientChannel::SendWithChannelHandle( void* transaction_state, int opcode, const iovec* send_vector, size_t send_count, const iovec* receive_vector, size_t receive_count) { Status int_status = SendAndReceive(transaction_state, opcode, send_vector, send_count, receive_vector, receive_count); Status status; if (status.PropagateError(int_status)) return status; auto* state = static_cast(transaction_state); LocalChannelHandle handle; if (state->GetLocalChannelHandle(int_status.get(), &handle)) { status.SetValue(std::move(handle)); } else { status.SetError(EINVAL); } return status; } FileReference ClientChannel::PushFileHandle(void* transaction_state, const LocalHandle& handle) { auto* state = static_cast(transaction_state); return state->PushFileHandle(handle.Borrow()); } FileReference ClientChannel::PushFileHandle(void* transaction_state, const BorrowedHandle& handle) { auto* state = static_cast(transaction_state); return state->PushFileHandle(handle.Duplicate()); } ChannelReference ClientChannel::PushChannelHandle( void* transaction_state, const LocalChannelHandle& handle) { auto* state = static_cast(transaction_state); return state->PushChannelHandle(handle.Borrow()); } ChannelReference ClientChannel::PushChannelHandle( void* transaction_state, const BorrowedChannelHandle& handle) { auto* state = static_cast(transaction_state); return state->PushChannelHandle(handle.Duplicate()); } bool ClientChannel::GetFileHandle(void* transaction_state, FileReference ref, LocalHandle* handle) const { auto* state = static_cast(transaction_state); return state->GetLocalFileHandle(ref, handle); } bool ClientChannel::GetChannelHandle(void* transaction_state, ChannelReference ref, LocalChannelHandle* handle) const { auto* state = static_cast(transaction_state); return state->GetLocalChannelHandle(ref, handle); } std::unique_ptr ClientChannel::TakeChannelParcelable() { if (!channel_handle_) return nullptr; if (auto* channel_data = ChannelManager::Get().GetChannelData(channel_handle_.value())) { auto fds = channel_data->TakeFds(); auto parcelable = std::make_unique( std::move(std::get<0>(fds)), std::move(std::get<1>(fds)), std::move(std::get<2>(fds))); // Here we need to explicitly close the channel handle so that the channel // won't get shutdown in the destructor, while the FDs in ChannelParcelable // can keep the channel alive so that new client can be created from it // later. channel_handle_.Close(); return parcelable; } else { return nullptr; } } } // namespace uds } // namespace pdx } // namespace android