blob: be99b64e304dbc9828752fce1c499278c4065fe9 [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/cpp/wire/wire_coding_traits.h>
namespace fidl::internal {
const CodingConfig kNullCodingConfig = {
.handle_metadata_stride = 0,
.encode_process_handle = nullptr,
.decode_process_handle = nullptr,
.close = [](fidl_handle_t handle) { ZX_PANIC("Should not have handles"); },
.close_many =
[](const fidl_handle_t* handles, size_t num_handles) {
ZX_ASSERT_MSG(num_handles == 0, "Should not have handles");
},
};
void WireDecodeUnknownEnvelope(WireDecoder* decoder, WirePosition position) {
const fidl_envelope_t* envelope = position.As<fidl_envelope_t>();
if (envelope->flags == 0) {
if (envelope->num_bytes % FIDL_ALIGNMENT != 0) {
decoder->SetError(kCodingErrorInvalidNumBytesSpecifiedInEnvelope);
return;
}
WirePosition new_position;
if (!decoder->Alloc(envelope->num_bytes, &new_position)) {
return;
}
} else if (envelope->flags != FIDL_ENVELOPE_FLAGS_INLINING_MASK) {
decoder->SetError(kCodingErrorInvalidInlineBit);
return;
}
decoder->CloseNextNHandles(envelope->num_handles);
}
fit::result<fidl::Error, WireEncoder::Result> WireEncode(
size_t inline_size, TopLevelEncodeFn encode_fn, const CodingConfig* coding_config, void* value,
zx_channel_iovec_t* iovecs, size_t iovec_capacity, fidl_handle_t* handles,
fidl_handle_metadata_t* handle_metadata, size_t handle_capacity, uint8_t* backing_buffer,
size_t backing_buffer_capacity) {
if (unlikely(value == nullptr)) {
return fit::error(fidl::Error::DecodeError(ZX_ERR_INVALID_ARGS, kCodingErrorNullIovecBuffer));
}
if (unlikely(iovecs == nullptr)) {
return fit::error(fidl::Error::DecodeError(ZX_ERR_INVALID_ARGS, kCodingErrorNullIovecBuffer));
}
if (unlikely(handle_capacity > 0 && handles == nullptr)) {
return fit::error(
fidl::Error::DecodeError(ZX_ERR_INVALID_ARGS, kCodingErrorNullHandleBufferButNonzeroCount));
}
if (unlikely(backing_buffer == nullptr)) {
return fit::error(fidl::Error::DecodeError(ZX_ERR_INVALID_ARGS, kCodingErrorNullByteBuffer));
}
WireEncoder encoder(coding_config, iovecs, iovec_capacity, handles, handle_metadata,
handle_capacity, backing_buffer, backing_buffer_capacity);
WirePosition position;
if (likely(encoder.Alloc(inline_size, &position))) {
encode_fn(&encoder, value, position);
}
return encoder.Finish();
}
fidl::Status WireDecode(::fidl::WireFormatMetadata metadata, size_t inline_size,
TopLevelDecodeFn decode_fn, ::fidl::EncodedMessage& message) {
if (fidl::Status status = EnsureSupportedWireFormat(metadata); !status.ok()) {
std::move(message).CloseHandles();
return status;
}
uint8_t* bytes = message.bytes().data();
size_t num_bytes = message.bytes().size();
fidl_handle_t* handles = message.handles();
fidl_handle_metadata_t* handle_metadata = message.raw_handle_metadata();
size_t num_handles = message.num_handles();
const internal::CodingConfig* coding_config =
message.transport_vtable() ? message.transport_vtable()->encoding_configuration
: &internal::kNullCodingConfig;
if (unlikely(bytes == nullptr)) {
std::move(message).CloseHandles();
return fidl::Status::DecodeError(ZX_ERR_INVALID_ARGS, kCodingErrorNullByteBuffer);
}
if (unlikely(num_handles > 0 && handles == nullptr)) {
return fidl::Status::DecodeError(ZX_ERR_INVALID_ARGS,
kCodingErrorNullHandleBufferButNonzeroCount);
}
WireDecoder decoder(coding_config, bytes, num_bytes, handles, handle_metadata, num_handles);
WirePosition position;
if (likely(decoder.Alloc(inline_size, &position))) {
decode_fn(&decoder, position);
}
if (unlikely(decoder.CurrentLength() < num_bytes)) {
decoder.SetError(kCodingErrorNotAllBytesConsumed);
}
if (unlikely(decoder.CurrentHandleCount() < num_handles)) {
decoder.SetError(kCodingErrorNotAllHandlesConsumed);
}
std::move(message).ReleaseHandles();
// Handles are closed in |Finish| in case of error.
return decoder.Finish();
}
::fidl::Status EnsureSupportedWireFormat(::fidl::WireFormatMetadata metadata) {
if (unlikely(!metadata.is_valid())) {
return ::fidl::Status::DecodeError(ZX_ERR_INVALID_ARGS, kCodingErrorInvalidWireFormatMetadata);
}
if (unlikely(metadata.wire_format_version() == fidl::internal::WireFormatVersion::kV1)) {
return ::fidl::Status::DecodeError(ZX_ERR_INVALID_ARGS, kCodingErrorDoesNotSupportV1Envelopes);
}
if (unlikely(metadata.wire_format_version() != fidl::internal::WireFormatVersion::kV2)) {
return ::fidl::Error::DecodeError(ZX_ERR_NOT_SUPPORTED,
kCodingErrorUnsupportedWireFormatVersion);
}
return ::fidl::Status::Ok();
}
} // namespace fidl::internal