blob: 61a2d4aea152f7698ff533762150759ee37ff344 [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "arc/vm/mojo_proxy/message_stream.h"
#include <string>
#include <utility>
#include <base/files/file_util.h>
#include <base/logging.h>
#include "arc/vm/mojo_proxy/file_descriptor_util.h"
namespace arc {
namespace {
// Receives data and FDs from the given socket FD and returns true when the
// buffer is filled successfully.
bool ReceiveData(int fd,
char* buf,
size_t size,
std::vector<base::ScopedFD>* fds) {
while (size > 0) {
ssize_t result =
fds ? Recvmsg(fd, buf, size, fds) : HANDLE_EINTR(read(fd, buf, size));
if (result <= 0) {
if (result == 0)
LOG(ERROR) << "Unexpected EOF while receiving data.";
else
PLOG(ERROR) << "Failed to receive data.";
return false;
}
fds = nullptr; // No need to receive FDs again.
buf += result;
size -= result;
}
return true;
}
} // namespace
MessageStream::MessageStream(base::ScopedFD fd) : fd_(std::move(fd)) {}
MessageStream::~MessageStream() = default;
bool MessageStream::Read(arc_proxy::MojoMessage* message,
std::vector<base::ScopedFD>* fds) {
// Receive FDs and the message size.
uint64_t size = 0;
if (!ReceiveData(fd_.get(), reinterpret_cast<char*>(&size), sizeof(size),
fds)) {
LOG(ERROR) << "Failed to receive message size.";
return false;
}
// Read and parse the message.
buf_.resize(size);
if (!base::ReadFromFD(fd_.get(), buf_.data(), buf_.size())) {
PLOG(ERROR) << "Failed to read a proto";
return false;
}
if (!message->ParseFromArray(buf_.data(), buf_.size())) {
LOG(ERROR) << "Failed to parse proto message";
return false;
}
return true;
}
bool MessageStream::Write(const arc_proxy::MojoMessage& message) {
const uint64_t size = message.ByteSizeLong();
buf_.resize(sizeof(size) + size);
struct Frame {
uint64_t size;
char data[];
};
Frame* frame = reinterpret_cast<Frame*>(buf_.data());
frame->size = size;
if (!message.SerializeToArray(frame->data, size)) {
LOG(ERROR) << "Failed to serialize proto.";
return false;
}
if (!base::WriteFileDescriptor(fd_.get(), buf_.data(), buf_.size())) {
PLOG(ERROR) << "Failed to write proto";
return false;
}
return true;
}
} // namespace arc