blob: 81aa41269286da64667dd49ad491ffa792992154 [file] [log] [blame]
// Copyright 2021 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_format_metadata.h>
#include <zircon/assert.h>
#include <cstring>
namespace fidl {
WireFormatMetadata WireFormatMetadata::FromOpaque(fidl_opaque_wire_format_metadata_t opaque) {
uint8_t bytes[8] = {};
memcpy(bytes, &opaque, sizeof(opaque));
WireFormatMetadata metadata;
metadata.disambiguator_ = bytes[0];
metadata.magic_number_ = bytes[1];
metadata.at_rest_flags_[0] = bytes[2];
metadata.at_rest_flags_[1] = bytes[3];
metadata.reserved_[0] = bytes[4];
metadata.reserved_[1] = bytes[5];
metadata.reserved_[2] = bytes[6];
metadata.reserved_[3] = bytes[7];
return metadata;
}
WireFormatMetadata WireFormatMetadata::FromTransactionalHeader(fidl_message_header_t header) {
WireFormatMetadata metadata;
metadata.disambiguator_ = 0;
metadata.magic_number_ = header.magic_number;
// See
// https://fuchsia.dev/fuchsia-src/contribute/governance/rfcs/0138_handling_unknown_interactions?hl=en#transactional-message-header-v4
//
// At-rest flags come first, followed by dynamic flags.
//
// Note: the V1, V2, and "V2 after unknown interactions" FIDL wire formats all
// store the at_rest flags in the same location. When a future FIDL revision
// change the location of the at_rest flags, this would need to be updated to
// be conditional on the magic number.
metadata.at_rest_flags_[0] = header.at_rest_flags[0];
metadata.at_rest_flags_[1] = header.at_rest_flags[1];
memset(metadata.reserved_, 0, sizeof(metadata.reserved_));
return metadata;
}
fidl_opaque_wire_format_metadata_t WireFormatMetadata::ToOpaque() const {
// Translate the metadata to a binary representation.
// We could use a for-loop or fancier serialization, but an array gives the
// most explicit control over the ABI.
uint8_t bytes[8] = {
disambiguator_, magic_number_, at_rest_flags_[0], at_rest_flags_[1],
reserved_[0], reserved_[1], reserved_[2], reserved_[3],
};
uint64_t opaque;
static_assert(sizeof(opaque) == sizeof(bytes), "Opaque metadata is 8 bytes");
memcpy(&opaque, bytes, sizeof(opaque));
return fidl_opaque_wire_format_metadata_t{opaque};
}
bool WireFormatMetadata::is_valid() const {
// Note: this method should be in sync with |fidl_validate_txn_header|.
// TODO(fxbug.dev/88366): Support the upcoming wire format magic in RFC-0138.
return magic_number_ == kFidlWireFormatMagicNumberInitial;
}
internal::WireFormatVersion WireFormatMetadata::wire_format_version() const {
ZX_ASSERT_MSG(is_valid(), "Invalid metadata %d %d %d", at_rest_flags_[0], at_rest_flags_[1],
magic_number_);
if ((at_rest_flags_[0] & FIDL_MESSAGE_HEADER_AT_REST_FLAGS_0_USE_VERSION_V2) == 0) {
return internal::WireFormatVersion::kV1;
}
return internal::WireFormatVersion::kV2;
}
::FidlWireFormatVersion WireFormatMetadata::c_wire_format_version() const {
switch (wire_format_version()) {
case internal::WireFormatVersion::kV1:
return FIDL_WIRE_FORMAT_VERSION_V1;
case internal::WireFormatVersion::kV2:
return FIDL_WIRE_FORMAT_VERSION_V2;
}
ZX_PANIC("Unsupported wire format version %d", static_cast<int>(wire_format_version()));
}
namespace internal {
// Constructs a |WireFormatMetadata| corresponding to the version.
WireFormatMetadata WireFormatMetadataForVersion(WireFormatVersion version) {
WireFormatMetadata metadata;
metadata.magic_number_ = kFidlWireFormatMagicNumberInitial;
switch (version) {
case WireFormatVersion::kV1:
return metadata;
case WireFormatVersion::kV2:
metadata.at_rest_flags_[0] = FIDL_MESSAGE_HEADER_AT_REST_FLAGS_0_USE_VERSION_V2;
return metadata;
}
ZX_PANIC("Unsupported wire format version %d", static_cast<int>(version));
}
} // namespace internal
} // namespace fidl