blob: 800726a03a18044b1f5e49707fe507fafe4843d2 [file] [log] [blame]
// Copyright 2022 The Fuchsia 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 <lib/fidl/cpp/wire/incoming_message.h>
#include <lib/fidl/txn_header.h>
#ifdef __Fuchsia__
#include <lib/fidl/cpp/wire/internal/transport_channel.h>
#else
#include <lib/fidl/cpp/wire/internal/transport_channel_host.h>
#endif // __Fuchsia__
namespace fidl {
namespace {
struct fidl_incoming_msg_impl {
cpp20::span<uint8_t> bytes;
fidl_handle_t* handles;
fidl_handle_metadata_t* handle_metadata;
uint32_t num_handles;
};
static_assert(sizeof(fidl_incoming_msg_impl) == sizeof(fidl_incoming_msg_t));
static_assert(alignof(fidl_incoming_msg_impl) == alignof(fidl_incoming_msg_t));
} // namespace
EncodedMessage EncodedMessage::Create(cpp20::span<uint8_t> bytes) {
return EncodedMessage(nullptr, bytes, nullptr, nullptr, 0);
}
EncodedMessage EncodedMessage::Create(cpp20::span<uint8_t> bytes, zx_handle_t* handles,
fidl_channel_handle_metadata_t* handle_metadata,
uint32_t handle_actual) {
return EncodedMessage(&internal::ChannelTransport::VTable, bytes, handles,
reinterpret_cast<fidl_handle_metadata_t*>(handle_metadata), handle_actual);
}
std::pair<cpp20::span<uint8_t>, cpp20::span<fidl_handle_t>> EncodedMessage::Release() && {
ZX_ASSERT(transport_vtable_->type == internal::fidl_transport_type::kChannel);
cpp20::span bytes = this->bytes();
cpp20::span handles{handles_, num_handles_};
std::move(*this).ReleaseHandles();
return {bytes, handles};
}
EncodedMessage::~EncodedMessage() { std::move(*this).CloseHandles(); }
void EncodedMessage::CloseHandles() && {
if (transport_vtable_) {
transport_vtable_->encoding_configuration->close_many(handles(), num_handles());
}
std::move(*this).ReleaseHandles();
}
EncodedMessage::EncodedMessage(const internal::TransportVTable* transport_vtable,
cpp20::span<uint8_t> bytes, fidl_handle_t* handles,
fidl_handle_metadata_t* handle_metadata, uint32_t handle_actual)
: transport_vtable_(transport_vtable),
bytes_(bytes),
handles_(handles),
num_handles_(handle_actual),
handle_metadata_(handle_metadata) {
ZX_DEBUG_ASSERT(bytes.size() < std::numeric_limits<uint32_t>::max());
}
IncomingHeaderAndMessage IncomingHeaderAndMessage::FromEncodedCMessage(
const fidl_incoming_msg_t& c_msg) {
const auto& msg = reinterpret_cast<const fidl_incoming_msg_impl&>(c_msg);
ZX_DEBUG_ASSERT(msg.bytes.size() >= sizeof(fidl_message_header_t));
return IncomingHeaderAndMessage(&internal::ChannelTransport::VTable, msg.bytes.data(),
static_cast<uint32_t>(msg.bytes.size()), msg.handles,
msg.handle_metadata, msg.num_handles);
}
IncomingHeaderAndMessage::~IncomingHeaderAndMessage() = default;
fidl_epitaph_t* IncomingHeaderAndMessage::maybe_epitaph() const {
ZX_DEBUG_ASSERT(ok());
if (unlikely(header()->ordinal == kFidlOrdinalEpitaph)) {
return reinterpret_cast<fidl_epitaph_t*>(bytes());
}
return nullptr;
}
fidl_incoming_msg_t IncomingHeaderAndMessage::ReleaseToEncodedCMessage() && {
ZX_DEBUG_ASSERT_MSG(status() == ZX_OK, "%s", status_string());
fidl_handle_t* handles = body_.handles();
uint32_t num_handles = body_.num_handles();
fidl_handle_metadata_t* handle_metadata = body_.raw_handle_metadata();
std::move(body_).ReleaseHandles();
fidl_incoming_msg_t msg;
reinterpret_cast<fidl_incoming_msg_impl&>(msg) = {
.bytes = bytes_,
.handles = handles,
.handle_metadata = handle_metadata,
.num_handles = num_handles,
};
return msg;
}
void IncomingHeaderAndMessage::CloseHandles() && { std::move(body_).CloseHandles(); }
EncodedMessage IncomingHeaderAndMessage::SkipTransactionHeader() && { return std::move(body_); }
IncomingHeaderAndMessage::IncomingHeaderAndMessage(const fidl::Status& failure)
: fidl::Status(failure), body_(EncodedMessage::Create({})) {
ZX_DEBUG_ASSERT(failure.status() != ZX_OK);
}
IncomingHeaderAndMessage::IncomingHeaderAndMessage(
const internal::TransportVTable* transport_vtable, uint8_t* bytes, uint32_t byte_actual,
fidl_handle_t* handles, fidl_handle_metadata_t* handle_metadata, uint32_t handle_actual)
: fidl::Status(fidl::Status::Ok()),
bytes_(cpp20::span{bytes, byte_actual}),
body_(bytes_.size() >= sizeof(fidl_message_header_t)
? EncodedMessage(transport_vtable, bytes_.subspan(sizeof(fidl_message_header_t)),
handles, handle_metadata, handle_actual)
: EncodedMessage::Create({})) {
ValidateHeader();
}
void IncomingHeaderAndMessage::ValidateHeader() {
if (byte_actual() < sizeof(fidl_message_header_t)) {
return SetStatus(fidl::Status::UnexpectedMessage(ZX_ERR_INVALID_ARGS,
::fidl::internal::kErrorInvalidHeader));
}
auto* hdr = header();
zx_status_t status = fidl_validate_txn_header(hdr);
if (status != ZX_OK) {
return SetStatus(
fidl::Status::UnexpectedMessage(status, ::fidl::internal::kErrorInvalidHeader));
}
// See
// https://fuchsia.dev/fuchsia-src/contribute/governance/rfcs/0053_epitaphs?hl=en#wire_format
if (unlikely(maybe_epitaph())) {
if (hdr->txid != 0) {
return SetStatus(fidl::Status::UnexpectedMessage(ZX_ERR_INVALID_ARGS,
::fidl::internal::kErrorInvalidHeader));
}
}
}
} // namespace fidl