790 lines
27 KiB
C++
790 lines
27 KiB
C++
#include "uds/service_endpoint.h"
|
|
|
|
#include <poll.h>
|
|
#include <sys/epoll.h>
|
|
#include <sys/eventfd.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <algorithm> // std::min
|
|
|
|
#include <android-base/logging.h>
|
|
#include <android-base/strings.h>
|
|
#include <cutils/sockets.h>
|
|
#include <pdx/service.h>
|
|
#include <selinux/selinux.h>
|
|
#include <uds/channel_manager.h>
|
|
#include <uds/client_channel_factory.h>
|
|
#include <uds/ipc_helper.h>
|
|
|
|
namespace {
|
|
|
|
constexpr int kMaxBackLogForSocketListen = 1;
|
|
|
|
using android::pdx::BorrowedChannelHandle;
|
|
using android::pdx::BorrowedHandle;
|
|
using android::pdx::ChannelReference;
|
|
using android::pdx::ErrorStatus;
|
|
using android::pdx::FileReference;
|
|
using android::pdx::LocalChannelHandle;
|
|
using android::pdx::LocalHandle;
|
|
using android::pdx::Status;
|
|
using android::pdx::uds::ChannelInfo;
|
|
using android::pdx::uds::ChannelManager;
|
|
|
|
struct MessageState {
|
|
bool GetLocalFileHandle(int index, LocalHandle* handle) {
|
|
if (index < 0) {
|
|
handle->Reset(index);
|
|
} else if (static_cast<size_t>(index) < request.file_descriptors.size()) {
|
|
*handle = std::move(request.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<size_t>(index) < request.channels.size()) {
|
|
auto& channel_info = request.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;
|
|
}
|
|
|
|
Status<FileReference> PushFileHandle(BorrowedHandle handle) {
|
|
if (!handle)
|
|
return handle.Get();
|
|
response.file_descriptors.push_back(std::move(handle));
|
|
return response.file_descriptors.size() - 1;
|
|
}
|
|
|
|
Status<ChannelReference> PushChannelHandle(BorrowedChannelHandle handle) {
|
|
if (!handle)
|
|
return handle.value();
|
|
|
|
if (auto* channel_data =
|
|
ChannelManager::Get().GetChannelData(handle.value())) {
|
|
ChannelInfo<BorrowedHandle> channel_info{
|
|
channel_data->data_fd(), channel_data->pollin_event_fd(),
|
|
channel_data->pollhup_event_fd()};
|
|
response.channels.push_back(std::move(channel_info));
|
|
return response.channels.size() - 1;
|
|
} else {
|
|
return ErrorStatus{EINVAL};
|
|
}
|
|
}
|
|
|
|
Status<ChannelReference> PushChannelHandle(BorrowedHandle data_fd,
|
|
BorrowedHandle pollin_event_fd,
|
|
BorrowedHandle pollhup_event_fd) {
|
|
if (!data_fd || !pollin_event_fd || !pollhup_event_fd)
|
|
return ErrorStatus{EINVAL};
|
|
ChannelInfo<BorrowedHandle> channel_info{std::move(data_fd),
|
|
std::move(pollin_event_fd),
|
|
std::move(pollhup_event_fd)};
|
|
response.channels.push_back(std::move(channel_info));
|
|
return response.channels.size() - 1;
|
|
}
|
|
|
|
Status<size_t> WriteData(const iovec* vector, size_t vector_length) {
|
|
size_t size = 0;
|
|
for (size_t i = 0; i < vector_length; i++) {
|
|
const auto* data = reinterpret_cast<const uint8_t*>(vector[i].iov_base);
|
|
response_data.insert(response_data.end(), data, data + vector[i].iov_len);
|
|
size += vector[i].iov_len;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
Status<size_t> ReadData(const iovec* vector, size_t vector_length) {
|
|
size_t size_remaining = request_data.size() - request_data_read_pos;
|
|
size_t size = 0;
|
|
for (size_t i = 0; i < vector_length && size_remaining > 0; i++) {
|
|
size_t size_to_copy = std::min(size_remaining, vector[i].iov_len);
|
|
memcpy(vector[i].iov_base, request_data.data() + request_data_read_pos,
|
|
size_to_copy);
|
|
size += size_to_copy;
|
|
request_data_read_pos += size_to_copy;
|
|
size_remaining -= size_to_copy;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
android::pdx::uds::RequestHeader<LocalHandle> request;
|
|
android::pdx::uds::ResponseHeader<BorrowedHandle> response;
|
|
std::vector<LocalHandle> sockets_to_close;
|
|
std::vector<uint8_t> request_data;
|
|
size_t request_data_read_pos{0};
|
|
std::vector<uint8_t> response_data;
|
|
};
|
|
|
|
} // anonymous namespace
|
|
|
|
namespace android {
|
|
namespace pdx {
|
|
namespace uds {
|
|
|
|
Endpoint::Endpoint(const std::string& endpoint_path, bool blocking,
|
|
bool use_init_socket_fd)
|
|
: endpoint_path_{ClientChannelFactory::GetEndpointPath(endpoint_path)},
|
|
is_blocking_{blocking} {
|
|
LocalHandle fd;
|
|
if (use_init_socket_fd) {
|
|
// Cut off the /dev/socket/ prefix from the full socket path and use the
|
|
// resulting "name" to retrieve the file descriptor for the socket created
|
|
// by the init process.
|
|
constexpr char prefix[] = "/dev/socket/";
|
|
CHECK(android::base::StartsWith(endpoint_path_, prefix))
|
|
<< "Endpoint::Endpoint: Socket name '" << endpoint_path_
|
|
<< "' must begin with '" << prefix << "'";
|
|
std::string socket_name = endpoint_path_.substr(sizeof(prefix) - 1);
|
|
fd.Reset(android_get_control_socket(socket_name.c_str()));
|
|
CHECK(fd.IsValid())
|
|
<< "Endpoint::Endpoint: Unable to obtain the control socket fd for '"
|
|
<< socket_name << "'";
|
|
fcntl(fd.Get(), F_SETFD, FD_CLOEXEC);
|
|
} else {
|
|
fd.Reset(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0));
|
|
CHECK(fd.IsValid()) << "Endpoint::Endpoint: Failed to create socket: "
|
|
<< strerror(errno);
|
|
|
|
sockaddr_un local;
|
|
local.sun_family = AF_UNIX;
|
|
strncpy(local.sun_path, endpoint_path_.c_str(), sizeof(local.sun_path));
|
|
local.sun_path[sizeof(local.sun_path) - 1] = '\0';
|
|
|
|
unlink(local.sun_path);
|
|
int ret =
|
|
bind(fd.Get(), reinterpret_cast<sockaddr*>(&local), sizeof(local));
|
|
CHECK_EQ(ret, 0) << "Endpoint::Endpoint: bind error: " << strerror(errno);
|
|
}
|
|
Init(std::move(fd));
|
|
}
|
|
|
|
Endpoint::Endpoint(LocalHandle socket_fd) { Init(std::move(socket_fd)); }
|
|
|
|
void Endpoint::Init(LocalHandle socket_fd) {
|
|
if (socket_fd) {
|
|
CHECK_EQ(listen(socket_fd.Get(), kMaxBackLogForSocketListen), 0)
|
|
<< "Endpoint::Endpoint: listen error: " << strerror(errno);
|
|
}
|
|
cancel_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
|
|
CHECK(cancel_event_fd_.IsValid())
|
|
<< "Endpoint::Endpoint: Failed to create event fd: " << strerror(errno);
|
|
|
|
epoll_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
|
|
CHECK(epoll_fd_.IsValid())
|
|
<< "Endpoint::Endpoint: Failed to create epoll fd: " << strerror(errno);
|
|
|
|
if (socket_fd) {
|
|
epoll_event socket_event;
|
|
socket_event.events = EPOLLIN | EPOLLRDHUP | EPOLLONESHOT;
|
|
socket_event.data.fd = socket_fd.Get();
|
|
int ret = epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, socket_fd.Get(),
|
|
&socket_event);
|
|
CHECK_EQ(ret, 0)
|
|
<< "Endpoint::Endpoint: Failed to add socket fd to epoll fd: "
|
|
<< strerror(errno);
|
|
}
|
|
|
|
epoll_event cancel_event;
|
|
cancel_event.events = EPOLLIN;
|
|
cancel_event.data.fd = cancel_event_fd_.Get();
|
|
|
|
int ret = epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, cancel_event_fd_.Get(),
|
|
&cancel_event);
|
|
CHECK_EQ(ret, 0)
|
|
<< "Endpoint::Endpoint: Failed to add cancel event fd to epoll fd: "
|
|
<< strerror(errno);
|
|
socket_fd_ = std::move(socket_fd);
|
|
}
|
|
|
|
void* Endpoint::AllocateMessageState() { return new MessageState; }
|
|
|
|
void Endpoint::FreeMessageState(void* state) {
|
|
delete static_cast<MessageState*>(state);
|
|
}
|
|
|
|
Status<void> Endpoint::AcceptConnection(Message* message) {
|
|
if (!socket_fd_)
|
|
return ErrorStatus(EBADF);
|
|
|
|
sockaddr_un remote;
|
|
socklen_t addrlen = sizeof(remote);
|
|
LocalHandle connection_fd{accept4(socket_fd_.Get(),
|
|
reinterpret_cast<sockaddr*>(&remote),
|
|
&addrlen, SOCK_CLOEXEC)};
|
|
if (!connection_fd) {
|
|
ALOGE("Endpoint::AcceptConnection: failed to accept connection: %s",
|
|
strerror(errno));
|
|
return ErrorStatus(errno);
|
|
}
|
|
|
|
LocalHandle local_socket;
|
|
LocalHandle remote_socket;
|
|
auto status = CreateChannelSocketPair(&local_socket, &remote_socket);
|
|
if (!status)
|
|
return status;
|
|
|
|
// Borrow the local channel handle before we move it into OnNewChannel().
|
|
BorrowedHandle channel_handle = local_socket.Borrow();
|
|
status = OnNewChannel(std::move(local_socket));
|
|
if (!status)
|
|
return status;
|
|
|
|
// Send the channel socket fd to the client.
|
|
ChannelConnectionInfo<LocalHandle> connection_info;
|
|
connection_info.channel_fd = std::move(remote_socket);
|
|
status = SendData(connection_fd.Borrow(), connection_info);
|
|
|
|
if (status) {
|
|
// Get the CHANNEL_OPEN message from client over the channel socket.
|
|
status = ReceiveMessageForChannel(channel_handle, message);
|
|
} else {
|
|
CloseChannel(GetChannelId(channel_handle));
|
|
}
|
|
|
|
// Don't need the connection socket anymore. Further communication should
|
|
// happen over the channel socket.
|
|
shutdown(connection_fd.Get(), SHUT_WR);
|
|
return status;
|
|
}
|
|
|
|
Status<void> Endpoint::SetService(Service* service) {
|
|
service_ = service;
|
|
return {};
|
|
}
|
|
|
|
Status<void> Endpoint::SetChannel(int channel_id, Channel* channel) {
|
|
std::lock_guard<std::mutex> autolock(channel_mutex_);
|
|
auto channel_data = channels_.find(channel_id);
|
|
if (channel_data == channels_.end())
|
|
return ErrorStatus{EINVAL};
|
|
channel_data->second.channel_state = channel;
|
|
return {};
|
|
}
|
|
|
|
Status<void> Endpoint::OnNewChannel(LocalHandle channel_fd) {
|
|
std::lock_guard<std::mutex> autolock(channel_mutex_);
|
|
Status<void> status;
|
|
status.PropagateError(OnNewChannelLocked(std::move(channel_fd), nullptr));
|
|
return status;
|
|
}
|
|
|
|
Status<std::pair<int32_t, Endpoint::ChannelData*>> Endpoint::OnNewChannelLocked(
|
|
LocalHandle channel_fd, Channel* channel_state) {
|
|
epoll_event event;
|
|
event.events = EPOLLIN | EPOLLRDHUP | EPOLLONESHOT;
|
|
event.data.fd = channel_fd.Get();
|
|
if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, channel_fd.Get(), &event) < 0) {
|
|
ALOGE(
|
|
"Endpoint::OnNewChannelLocked: Failed to add channel to endpoint: %s\n",
|
|
strerror(errno));
|
|
return ErrorStatus(errno);
|
|
}
|
|
ChannelData channel_data;
|
|
channel_data.data_fd = std::move(channel_fd);
|
|
channel_data.channel_state = channel_state;
|
|
for (;;) {
|
|
// Try new channel IDs until we find one which is not already in the map.
|
|
if (last_channel_id_++ == std::numeric_limits<int32_t>::max())
|
|
last_channel_id_ = 1;
|
|
auto iter = channels_.lower_bound(last_channel_id_);
|
|
if (iter == channels_.end() || iter->first != last_channel_id_) {
|
|
channel_fd_to_id_.emplace(channel_data.data_fd.Get(), last_channel_id_);
|
|
iter = channels_.emplace_hint(iter, last_channel_id_,
|
|
std::move(channel_data));
|
|
return std::make_pair(last_channel_id_, &iter->second);
|
|
}
|
|
}
|
|
}
|
|
|
|
Status<void> Endpoint::ReenableEpollEvent(const BorrowedHandle& fd) {
|
|
epoll_event event;
|
|
event.events = EPOLLIN | EPOLLRDHUP | EPOLLONESHOT;
|
|
event.data.fd = fd.Get();
|
|
if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_MOD, fd.Get(), &event) < 0) {
|
|
ALOGE(
|
|
"Endpoint::ReenableEpollEvent: Failed to re-enable channel to "
|
|
"endpoint: %s\n",
|
|
strerror(errno));
|
|
return ErrorStatus(errno);
|
|
}
|
|
return {};
|
|
}
|
|
|
|
Status<void> Endpoint::CloseChannel(int channel_id) {
|
|
std::lock_guard<std::mutex> autolock(channel_mutex_);
|
|
return CloseChannelLocked(channel_id);
|
|
}
|
|
|
|
Status<void> Endpoint::CloseChannelLocked(int32_t channel_id) {
|
|
ALOGD_IF(TRACE, "Endpoint::CloseChannelLocked: channel_id=%d", channel_id);
|
|
|
|
auto iter = channels_.find(channel_id);
|
|
if (iter == channels_.end())
|
|
return ErrorStatus{EINVAL};
|
|
|
|
int channel_fd = iter->second.data_fd.Get();
|
|
Status<void> status;
|
|
epoll_event ee; // See BUGS in man 2 epoll_ctl.
|
|
if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, channel_fd, &ee) < 0) {
|
|
status.SetError(errno);
|
|
ALOGE(
|
|
"Endpoint::CloseChannelLocked: Failed to remove channel from endpoint: "
|
|
"%s\n",
|
|
strerror(errno));
|
|
} else {
|
|
status.SetValue();
|
|
}
|
|
|
|
channel_fd_to_id_.erase(channel_fd);
|
|
channels_.erase(iter);
|
|
return status;
|
|
}
|
|
|
|
Status<void> Endpoint::ModifyChannelEvents(int channel_id, int clear_mask,
|
|
int set_mask) {
|
|
std::lock_guard<std::mutex> autolock(channel_mutex_);
|
|
|
|
auto search = channels_.find(channel_id);
|
|
if (search != channels_.end()) {
|
|
auto& channel_data = search->second;
|
|
channel_data.event_set.ModifyEvents(clear_mask, set_mask);
|
|
return {};
|
|
}
|
|
|
|
return ErrorStatus{EINVAL};
|
|
}
|
|
|
|
Status<void> Endpoint::CreateChannelSocketPair(LocalHandle* local_socket,
|
|
LocalHandle* remote_socket) {
|
|
Status<void> status;
|
|
char* endpoint_context = nullptr;
|
|
// Make sure the channel socket has the correct SELinux label applied.
|
|
// Here we get the label from the endpoint file descriptor, which should be
|
|
// something like "u:object_r:pdx_service_endpoint_socket:s0" and replace
|
|
// "endpoint" with "channel" to produce the channel label such as this:
|
|
// "u:object_r:pdx_service_channel_socket:s0".
|
|
if (fgetfilecon_raw(socket_fd_.Get(), &endpoint_context) > 0) {
|
|
std::string channel_context = endpoint_context;
|
|
freecon(endpoint_context);
|
|
const std::string suffix = "_endpoint_socket";
|
|
auto pos = channel_context.find(suffix);
|
|
if (pos != std::string::npos) {
|
|
channel_context.replace(pos, suffix.size(), "_channel_socket");
|
|
} else {
|
|
ALOGW(
|
|
"Endpoint::CreateChannelSocketPair: Endpoint security context '%s' "
|
|
"does not contain expected substring '%s'",
|
|
channel_context.c_str(), suffix.c_str());
|
|
}
|
|
ALOGE_IF(setsockcreatecon_raw(channel_context.c_str()) == -1,
|
|
"Endpoint::CreateChannelSocketPair: Failed to set channel socket "
|
|
"security context: %s",
|
|
strerror(errno));
|
|
} else {
|
|
ALOGE(
|
|
"Endpoint::CreateChannelSocketPair: Failed to obtain the endpoint "
|
|
"socket's security context: %s",
|
|
strerror(errno));
|
|
}
|
|
|
|
int channel_pair[2] = {};
|
|
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, channel_pair) == -1) {
|
|
ALOGE("Endpoint::CreateChannelSocketPair: Failed to create socket pair: %s",
|
|
strerror(errno));
|
|
status.SetError(errno);
|
|
return status;
|
|
}
|
|
|
|
setsockcreatecon_raw(nullptr);
|
|
|
|
local_socket->Reset(channel_pair[0]);
|
|
remote_socket->Reset(channel_pair[1]);
|
|
|
|
int optval = 1;
|
|
if (setsockopt(local_socket->Get(), SOL_SOCKET, SO_PASSCRED, &optval,
|
|
sizeof(optval)) == -1) {
|
|
ALOGE(
|
|
"Endpoint::CreateChannelSocketPair: Failed to enable the receiving of "
|
|
"the credentials for channel %d: %s",
|
|
local_socket->Get(), strerror(errno));
|
|
status.SetError(errno);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
Status<RemoteChannelHandle> Endpoint::PushChannel(Message* message,
|
|
int /*flags*/,
|
|
Channel* channel,
|
|
int* channel_id) {
|
|
LocalHandle local_socket;
|
|
LocalHandle remote_socket;
|
|
auto status = CreateChannelSocketPair(&local_socket, &remote_socket);
|
|
if (!status)
|
|
return status.error_status();
|
|
|
|
std::lock_guard<std::mutex> autolock(channel_mutex_);
|
|
auto channel_data_status =
|
|
OnNewChannelLocked(std::move(local_socket), channel);
|
|
if (!channel_data_status)
|
|
return channel_data_status.error_status();
|
|
|
|
ChannelData* channel_data;
|
|
std::tie(*channel_id, channel_data) = channel_data_status.take();
|
|
|
|
// Flags are ignored for now.
|
|
// TODO(xiaohuit): Implement those.
|
|
|
|
auto* state = static_cast<MessageState*>(message->GetState());
|
|
Status<ChannelReference> ref = state->PushChannelHandle(
|
|
remote_socket.Borrow(), channel_data->event_set.pollin_event_fd(),
|
|
channel_data->event_set.pollhup_event_fd());
|
|
if (!ref)
|
|
return ref.error_status();
|
|
state->sockets_to_close.push_back(std::move(remote_socket));
|
|
return RemoteChannelHandle{ref.get()};
|
|
}
|
|
|
|
Status<int> Endpoint::CheckChannel(const Message* /*message*/,
|
|
ChannelReference /*ref*/,
|
|
Channel** /*channel*/) {
|
|
// TODO(xiaohuit): Implement this.
|
|
return ErrorStatus(EFAULT);
|
|
}
|
|
|
|
Channel* Endpoint::GetChannelState(int32_t channel_id) {
|
|
std::lock_guard<std::mutex> autolock(channel_mutex_);
|
|
auto channel_data = channels_.find(channel_id);
|
|
return (channel_data != channels_.end()) ? channel_data->second.channel_state
|
|
: nullptr;
|
|
}
|
|
|
|
BorrowedHandle Endpoint::GetChannelSocketFd(int32_t channel_id) {
|
|
std::lock_guard<std::mutex> autolock(channel_mutex_);
|
|
BorrowedHandle handle;
|
|
auto channel_data = channels_.find(channel_id);
|
|
if (channel_data != channels_.end())
|
|
handle = channel_data->second.data_fd.Borrow();
|
|
return handle;
|
|
}
|
|
|
|
Status<std::pair<BorrowedHandle, BorrowedHandle>> Endpoint::GetChannelEventFd(
|
|
int32_t channel_id) {
|
|
std::lock_guard<std::mutex> autolock(channel_mutex_);
|
|
auto channel_data = channels_.find(channel_id);
|
|
if (channel_data != channels_.end()) {
|
|
return {{channel_data->second.event_set.pollin_event_fd(),
|
|
channel_data->second.event_set.pollhup_event_fd()}};
|
|
}
|
|
return ErrorStatus(ENOENT);
|
|
}
|
|
|
|
int32_t Endpoint::GetChannelId(const BorrowedHandle& channel_fd) {
|
|
std::lock_guard<std::mutex> autolock(channel_mutex_);
|
|
auto iter = channel_fd_to_id_.find(channel_fd.Get());
|
|
return (iter != channel_fd_to_id_.end()) ? iter->second : -1;
|
|
}
|
|
|
|
Status<void> Endpoint::ReceiveMessageForChannel(
|
|
const BorrowedHandle& channel_fd, Message* message) {
|
|
RequestHeader<LocalHandle> request;
|
|
int32_t channel_id = GetChannelId(channel_fd);
|
|
auto status = ReceiveData(channel_fd.Borrow(), &request);
|
|
if (!status) {
|
|
if (status.error() == ESHUTDOWN) {
|
|
BuildCloseMessage(channel_id, message);
|
|
return {};
|
|
} else {
|
|
CloseChannel(channel_id);
|
|
return status;
|
|
}
|
|
}
|
|
|
|
MessageInfo info;
|
|
info.pid = request.cred.pid;
|
|
info.tid = -1;
|
|
info.cid = channel_id;
|
|
info.mid = request.is_impulse ? Message::IMPULSE_MESSAGE_ID
|
|
: GetNextAvailableMessageId();
|
|
info.euid = request.cred.uid;
|
|
info.egid = request.cred.gid;
|
|
info.op = request.op;
|
|
info.flags = 0;
|
|
info.service = service_;
|
|
info.channel = GetChannelState(channel_id);
|
|
if (info.channel != nullptr) {
|
|
info.channel->SetActiveProcessId(request.cred.pid);
|
|
}
|
|
info.send_len = request.send_len;
|
|
info.recv_len = request.max_recv_len;
|
|
info.fd_count = request.file_descriptors.size();
|
|
static_assert(sizeof(info.impulse) == request.impulse_payload.size(),
|
|
"Impulse payload sizes must be the same in RequestHeader and "
|
|
"MessageInfo");
|
|
memcpy(info.impulse, request.impulse_payload.data(),
|
|
request.impulse_payload.size());
|
|
*message = Message{info};
|
|
auto* state = static_cast<MessageState*>(message->GetState());
|
|
state->request = std::move(request);
|
|
if (state->request.send_len > 0 && !state->request.is_impulse) {
|
|
state->request_data.resize(state->request.send_len);
|
|
status = ReceiveData(channel_fd, state->request_data.data(),
|
|
state->request_data.size());
|
|
}
|
|
|
|
if (status && state->request.is_impulse)
|
|
status = ReenableEpollEvent(channel_fd);
|
|
|
|
if (!status) {
|
|
if (status.error() == ESHUTDOWN) {
|
|
BuildCloseMessage(channel_id, message);
|
|
return {};
|
|
} else {
|
|
CloseChannel(channel_id);
|
|
return status;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
void Endpoint::BuildCloseMessage(int32_t channel_id, Message* message) {
|
|
ALOGD_IF(TRACE, "Endpoint::BuildCloseMessage: channel_id=%d", channel_id);
|
|
MessageInfo info;
|
|
info.pid = -1;
|
|
info.tid = -1;
|
|
info.cid = channel_id;
|
|
info.mid = GetNextAvailableMessageId();
|
|
info.euid = -1;
|
|
info.egid = -1;
|
|
info.op = opcodes::CHANNEL_CLOSE;
|
|
info.flags = 0;
|
|
info.service = service_;
|
|
info.channel = GetChannelState(channel_id);
|
|
info.send_len = 0;
|
|
info.recv_len = 0;
|
|
info.fd_count = 0;
|
|
*message = Message{info};
|
|
}
|
|
|
|
Status<void> Endpoint::MessageReceive(Message* message) {
|
|
// Receive at most one event from the epoll set. This should prevent multiple
|
|
// dispatch threads from attempting to handle messages on the same socket at
|
|
// the same time.
|
|
epoll_event event;
|
|
int count = RETRY_EINTR(
|
|
epoll_wait(epoll_fd_.Get(), &event, 1, is_blocking_ ? -1 : 0));
|
|
if (count < 0) {
|
|
ALOGE("Endpoint::MessageReceive: Failed to wait for epoll events: %s\n",
|
|
strerror(errno));
|
|
return ErrorStatus{errno};
|
|
} else if (count == 0) {
|
|
return ErrorStatus{ETIMEDOUT};
|
|
}
|
|
|
|
if (event.data.fd == cancel_event_fd_.Get()) {
|
|
return ErrorStatus{ESHUTDOWN};
|
|
}
|
|
|
|
if (socket_fd_ && event.data.fd == socket_fd_.Get()) {
|
|
auto status = AcceptConnection(message);
|
|
auto reenable_status = ReenableEpollEvent(socket_fd_.Borrow());
|
|
if (!reenable_status)
|
|
return reenable_status;
|
|
return status;
|
|
}
|
|
|
|
BorrowedHandle channel_fd{event.data.fd};
|
|
return ReceiveMessageForChannel(channel_fd, message);
|
|
}
|
|
|
|
Status<void> Endpoint::MessageReply(Message* message, int return_code) {
|
|
const int32_t channel_id = message->GetChannelId();
|
|
auto channel_socket = GetChannelSocketFd(channel_id);
|
|
if (!channel_socket)
|
|
return ErrorStatus{EBADF};
|
|
|
|
auto* state = static_cast<MessageState*>(message->GetState());
|
|
switch (message->GetOp()) {
|
|
case opcodes::CHANNEL_CLOSE:
|
|
return CloseChannel(channel_id);
|
|
|
|
case opcodes::CHANNEL_OPEN:
|
|
if (return_code < 0) {
|
|
return CloseChannel(channel_id);
|
|
} else {
|
|
// Open messages do not have a payload and may not transfer any channels
|
|
// or file descriptors on behalf of the service.
|
|
state->response_data.clear();
|
|
state->response.file_descriptors.clear();
|
|
state->response.channels.clear();
|
|
|
|
// Return the channel event-related fds in a single ChannelInfo entry
|
|
// with an empty data_fd member.
|
|
auto status = GetChannelEventFd(channel_id);
|
|
if (!status)
|
|
return status.error_status();
|
|
|
|
auto handles = status.take();
|
|
state->response.channels.push_back({BorrowedHandle(),
|
|
std::move(handles.first),
|
|
std::move(handles.second)});
|
|
return_code = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
state->response.ret_code = return_code;
|
|
state->response.recv_len = state->response_data.size();
|
|
auto status = SendData(channel_socket, state->response);
|
|
if (status && !state->response_data.empty()) {
|
|
status = SendData(channel_socket, state->response_data.data(),
|
|
state->response_data.size());
|
|
}
|
|
|
|
if (status)
|
|
status = ReenableEpollEvent(channel_socket);
|
|
|
|
return status;
|
|
}
|
|
|
|
Status<void> Endpoint::MessageReplyFd(Message* message, unsigned int push_fd) {
|
|
auto* state = static_cast<MessageState*>(message->GetState());
|
|
auto ref = state->PushFileHandle(BorrowedHandle{static_cast<int>(push_fd)});
|
|
if (!ref)
|
|
return ref.error_status();
|
|
return MessageReply(message, ref.get());
|
|
}
|
|
|
|
Status<void> Endpoint::MessageReplyChannelHandle(
|
|
Message* message, const LocalChannelHandle& handle) {
|
|
auto* state = static_cast<MessageState*>(message->GetState());
|
|
auto ref = state->PushChannelHandle(handle.Borrow());
|
|
if (!ref)
|
|
return ref.error_status();
|
|
return MessageReply(message, ref.get());
|
|
}
|
|
|
|
Status<void> Endpoint::MessageReplyChannelHandle(
|
|
Message* message, const BorrowedChannelHandle& handle) {
|
|
auto* state = static_cast<MessageState*>(message->GetState());
|
|
auto ref = state->PushChannelHandle(handle.Duplicate());
|
|
if (!ref)
|
|
return ref.error_status();
|
|
return MessageReply(message, ref.get());
|
|
}
|
|
|
|
Status<void> Endpoint::MessageReplyChannelHandle(
|
|
Message* message, const RemoteChannelHandle& handle) {
|
|
return MessageReply(message, handle.value());
|
|
}
|
|
|
|
Status<size_t> Endpoint::ReadMessageData(Message* message, const iovec* vector,
|
|
size_t vector_length) {
|
|
auto* state = static_cast<MessageState*>(message->GetState());
|
|
return state->ReadData(vector, vector_length);
|
|
}
|
|
|
|
Status<size_t> Endpoint::WriteMessageData(Message* message, const iovec* vector,
|
|
size_t vector_length) {
|
|
auto* state = static_cast<MessageState*>(message->GetState());
|
|
return state->WriteData(vector, vector_length);
|
|
}
|
|
|
|
Status<FileReference> Endpoint::PushFileHandle(Message* message,
|
|
const LocalHandle& handle) {
|
|
auto* state = static_cast<MessageState*>(message->GetState());
|
|
return state->PushFileHandle(handle.Borrow());
|
|
}
|
|
|
|
Status<FileReference> Endpoint::PushFileHandle(Message* message,
|
|
const BorrowedHandle& handle) {
|
|
auto* state = static_cast<MessageState*>(message->GetState());
|
|
return state->PushFileHandle(handle.Duplicate());
|
|
}
|
|
|
|
Status<FileReference> Endpoint::PushFileHandle(Message* /*message*/,
|
|
const RemoteHandle& handle) {
|
|
return handle.Get();
|
|
}
|
|
|
|
Status<ChannelReference> Endpoint::PushChannelHandle(
|
|
Message* message, const LocalChannelHandle& handle) {
|
|
auto* state = static_cast<MessageState*>(message->GetState());
|
|
return state->PushChannelHandle(handle.Borrow());
|
|
}
|
|
|
|
Status<ChannelReference> Endpoint::PushChannelHandle(
|
|
Message* message, const BorrowedChannelHandle& handle) {
|
|
auto* state = static_cast<MessageState*>(message->GetState());
|
|
return state->PushChannelHandle(handle.Duplicate());
|
|
}
|
|
|
|
Status<ChannelReference> Endpoint::PushChannelHandle(
|
|
Message* /*message*/, const RemoteChannelHandle& handle) {
|
|
return handle.value();
|
|
}
|
|
|
|
LocalHandle Endpoint::GetFileHandle(Message* message, FileReference ref) const {
|
|
LocalHandle handle;
|
|
auto* state = static_cast<MessageState*>(message->GetState());
|
|
state->GetLocalFileHandle(ref, &handle);
|
|
return handle;
|
|
}
|
|
|
|
LocalChannelHandle Endpoint::GetChannelHandle(Message* message,
|
|
ChannelReference ref) const {
|
|
LocalChannelHandle handle;
|
|
auto* state = static_cast<MessageState*>(message->GetState());
|
|
state->GetLocalChannelHandle(ref, &handle);
|
|
return handle;
|
|
}
|
|
|
|
Status<void> Endpoint::Cancel() {
|
|
if (eventfd_write(cancel_event_fd_.Get(), 1) < 0)
|
|
return ErrorStatus{errno};
|
|
return {};
|
|
}
|
|
|
|
std::unique_ptr<Endpoint> Endpoint::Create(const std::string& endpoint_path,
|
|
mode_t /*unused_mode*/,
|
|
bool blocking) {
|
|
return std::unique_ptr<Endpoint>(new Endpoint(endpoint_path, blocking));
|
|
}
|
|
|
|
std::unique_ptr<Endpoint> Endpoint::CreateAndBindSocket(
|
|
const std::string& endpoint_path, bool blocking) {
|
|
return std::unique_ptr<Endpoint>(
|
|
new Endpoint(endpoint_path, blocking, false));
|
|
}
|
|
|
|
std::unique_ptr<Endpoint> Endpoint::CreateFromSocketFd(LocalHandle socket_fd) {
|
|
return std::unique_ptr<Endpoint>(new Endpoint(std::move(socket_fd)));
|
|
}
|
|
|
|
Status<void> Endpoint::RegisterNewChannelForTests(LocalHandle channel_fd) {
|
|
int optval = 1;
|
|
if (setsockopt(channel_fd.Get(), SOL_SOCKET, SO_PASSCRED, &optval,
|
|
sizeof(optval)) == -1) {
|
|
ALOGE(
|
|
"Endpoint::RegisterNewChannelForTests: Failed to enable the receiving"
|
|
"of the credentials for channel %d: %s",
|
|
channel_fd.Get(), strerror(errno));
|
|
return ErrorStatus(errno);
|
|
}
|
|
return OnNewChannel(std::move(channel_fd));
|
|
}
|
|
|
|
} // namespace uds
|
|
} // namespace pdx
|
|
} // namespace android
|