#include "mojo/public/cpp/bindings/pipe_control_message_handler.h"
#include "base/logging.h"
#include "mojo/public/cpp/bindings/interface_id.h"
#include "mojo/public/cpp/bindings/lib/serialization.h"
#include "mojo/public/cpp/bindings/lib/validation_context.h"
#include "mojo/public/cpp/bindings/lib/validation_util.h"
#include "mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h"
#include "mojo/public/interfaces/bindings/pipe_control_messages.mojom.h"
namespace mojo {
PipeControlMessageHandler::PipeControlMessageHandler(
PipeControlMessageHandlerDelegate* delegate)
: delegate_(delegate) {}
PipeControlMessageHandler::~PipeControlMessageHandler() {}
void PipeControlMessageHandler::SetDescription(const std::string& description) {
description_ = description;
}
bool PipeControlMessageHandler::IsPipeControlMessage(const Message* message) {
return !IsValidInterfaceId(message->interface_id());
}
std::optional<InterfaceId>
PipeControlMessageHandler::IsPeerAssociatedEndpointClosedEvent(
const Message& message) {
if (!IsPipeControlMessage(&message)) {
return std::nullopt;
}
if (message.name() != pipe_control::kRunOrClosePipeMessageId) {
return std::nullopt;
}
pipe_control::RunOrClosePipeMessageParamsPtr params_ptr;
if (!pipe_control::RunOrClosePipeMessageParams::Deserialize(
message.payload(), message.payload_num_bytes(), ¶ms_ptr)) {
return std::nullopt;
}
if (!params_ptr ||
!params_ptr->input->is_peer_associated_endpoint_closed_event()) {
return std::nullopt;
}
const auto& event =
params_ptr->input->get_peer_associated_endpoint_closed_event();
return event->id;
}
bool PipeControlMessageHandler::Accept(Message* message) {
if (!Validate(message))
return false;
if (message->name() == pipe_control::kRunOrClosePipeMessageId)
return RunOrClosePipe(message);
NOTREACHED();
}
bool PipeControlMessageHandler::Validate(Message* message) {
internal::ValidationContext validation_context(
message->payload(), message->payload_num_bytes(),
message->handles()->size(), 0, message, description_.c_str());
if (message->name() == pipe_control::kRunOrClosePipeMessageId) {
if (!internal::ValidateMessageIsRequestWithoutResponse(
message, &validation_context)) {
return false;
}
return internal::ValidateMessagePayload<
pipe_control::internal::RunOrClosePipeMessageParams_Data>(
message, &validation_context);
}
return false;
}
bool PipeControlMessageHandler::RunOrClosePipe(Message* message) {
pipe_control::internal::RunOrClosePipeMessageParams_Data* params =
reinterpret_cast<
pipe_control::internal::RunOrClosePipeMessageParams_Data*>(
message->mutable_payload());
pipe_control::RunOrClosePipeMessageParamsPtr params_ptr;
internal::Deserialize<pipe_control::RunOrClosePipeMessageParamsDataView>(
params, ¶ms_ptr, message);
if (params_ptr->input->is_peer_associated_endpoint_closed_event()) {
const auto& event =
params_ptr->input->get_peer_associated_endpoint_closed_event();
std::optional<DisconnectReason> reason;
if (event->disconnect_reason) {
reason.emplace(event->disconnect_reason->custom_reason,
event->disconnect_reason->description);
}
return delegate_->OnPeerAssociatedEndpointClosed(event->id, reason);
}
if (params_ptr->input->is_flush_async()) {
return true;
}
if (params_ptr->input->is_pause_until_flush_completes()) {
return delegate_->WaitForFlushToComplete(std::move(
params_ptr->input->get_pause_until_flush_completes()->flush_pipe));
}
DVLOG(1) << "Unsupported command in a RunOrClosePipe message pipe control "
<< "message. Closing the pipe.";
return false;
}
}