// Copyright 2014 The Chromium 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 "ipc/ipc_message_pipe_reader.h"
#include <stdint.h>
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ipc/ipc_channel_mojo.h"
#include "mojo/public/cpp/bindings/message.h"
namespace IPC {
namespace internal {
MessagePipeReader::MessagePipeReader(
mojo::MessagePipeHandle pipe,
mojom::ChannelAssociatedPtr sender,
mojo::AssociatedInterfaceRequest<mojom::Channel> receiver,
MessagePipeReader::Delegate* delegate)
: delegate_(delegate),
sender_(std::move(sender)),
binding_(this, std::move(receiver)) {
sender_.set_connection_error_handler(
base::Bind(&MessagePipeReader::OnPipeError, base::Unretained(this),
MOJO_RESULT_FAILED_PRECONDITION));
binding_.set_connection_error_handler(
base::Bind(&MessagePipeReader::OnPipeError, base::Unretained(this),
MOJO_RESULT_FAILED_PRECONDITION));
}
MessagePipeReader::~MessagePipeReader() {
DCHECK(thread_checker_.CalledOnValidThread());
// The pipe should be closed before deletion.
}
void MessagePipeReader::Close() {
DCHECK(thread_checker_.CalledOnValidThread());
sender_.reset();
if (binding_.is_bound())
binding_.Close();
}
bool MessagePipeReader::Send(std::unique_ptr<Message> message) {
CHECK(message->IsValid());
TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
"MessagePipeReader::Send", message->flags(),
TRACE_EVENT_FLAG_FLOW_OUT);
base::Optional<std::vector<mojo::native::SerializedHandlePtr>> handles;
MojoResult result = MOJO_RESULT_OK;
result = ChannelMojo::ReadFromMessageAttachmentSet(message.get(), &handles);
if (result != MOJO_RESULT_OK)
return false;
if (!sender_)
return false;
sender_->Receive(MessageView(*message, std::move(handles)));
DVLOG(4) << "Send " << message->type() << ": " << message->size();
return true;
}
void MessagePipeReader::GetRemoteInterface(
const std::string& name,
mojo::ScopedInterfaceEndpointHandle handle) {
if (!sender_.is_bound())
return;
sender_->GetAssociatedInterface(
name, mojom::GenericInterfaceAssociatedRequest(std::move(handle)));
}
void MessagePipeReader::SetPeerPid(int32_t peer_pid) {
delegate_->OnPeerPidReceived(peer_pid);
}
void MessagePipeReader::Receive(MessageView message_view) {
if (!message_view.size()) {
delegate_->OnBrokenDataReceived();
return;
}
Message message(message_view.data(), message_view.size());
if (!message.IsValid()) {
delegate_->OnBrokenDataReceived();
return;
}
DVLOG(4) << "Receive " << message.type() << ": " << message.size();
MojoResult write_result = ChannelMojo::WriteToMessageAttachmentSet(
message_view.TakeHandles(), &message);
if (write_result != MOJO_RESULT_OK) {
OnPipeError(write_result);
return;
}
TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
"MessagePipeReader::Receive",
message.flags(),
TRACE_EVENT_FLAG_FLOW_IN);
delegate_->OnMessageReceived(message);
}
void MessagePipeReader::GetAssociatedInterface(
const std::string& name,
mojom::GenericInterfaceAssociatedRequest request) {
DCHECK(thread_checker_.CalledOnValidThread());
if (delegate_)
delegate_->OnAssociatedInterfaceRequest(name, request.PassHandle());
}
void MessagePipeReader::OnPipeError(MojoResult error) {
DCHECK(thread_checker_.CalledOnValidThread());
Close();
// NOTE: The delegate call below may delete |this|.
if (delegate_)
delegate_->OnPipeError();
}
} // namespace internal
} // namespace IPC