blob: 810eb196ca03397c061c1243ab8cffde95636205 [file] [log] [blame]
#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