blob: 52d0ec5defe48dda7b02e98b4065345dfe04a5d9 [file] [log] [blame]
// Copyright 2018 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.
#ifndef LIB_FIDL_LLCPP_DECODED_MESSAGE_H_
#define LIB_FIDL_LLCPP_DECODED_MESSAGE_H_
#include <lib/fidl/coding.h>
#include <lib/fidl/llcpp/encoded_message.h>
#include <lib/fidl/llcpp/traits.h>
#include <type_traits>
#include <zircon/fidl.h>
namespace fidl {
// `DecodedMessage` manages a linearized FIDL message in decoded form.
// It takes care of releasing all handles which were not consumed
// (std::moved from the decoded FIDL struct) when it goes out of scope.
template <typename FidlType>
class DecodedMessage final {
static_assert(IsFidlType<FidlType>::value, "Only FIDL types allowed here");
static_assert(FidlType::MaxSize > 0, "Positive message size");
public:
// Instantiates an empty message.
// To populate this message, decode from an EncodedMessage object.
DecodedMessage() = default;
// Instantiates a DecodedMessage which points to a buffer region with caller-managed memory.
// The buffer region is assumed to contain a linearized FIDL message with valid pointers.
// This does not take ownership of that buffer region.
// But it does take ownership of the handles within the buffer.
DecodedMessage(BytePart bytes) :
bytes_(std::move(bytes)) { }
DecodedMessage(DecodedMessage&& other) = default;
DecodedMessage& operator=(DecodedMessage&& other) = default;
DecodedMessage(const DecodedMessage& other) = delete;
DecodedMessage& operator=(const DecodedMessage& other) = delete;
~DecodedMessage() {
CloseHandles();
}
// Keeps track of a new buffer region with caller-managed memory.
// The buffer region is assumed to contain a linearized FIDL message with valid pointers.
// This does not take ownership of that buffer region.
// But it does take ownership of the handles within the buffer.
void Reset(BytePart bytes) {
CloseHandles();
bytes_ = std::move(bytes);
}
// Consumes an encoded message object containing FIDL encoded bytes and handles.
// The current buffer region in DecodedMessage is always released.
// Uses the FIDL encoding tables to deserialize the message in-place.
// If the message is invalid, discards the buffer and returns an error.
zx_status_t DecodeFrom(EncodedMessage<FidlType>* msg, const char** out_error_msg) {
// Clear any existing message.
CloseHandles();
bytes_ = BytePart();
zx_status_t status = fidl_decode(FidlType::type,
msg->bytes().data(), msg->bytes().actual(),
msg->handles().data(), msg->handles().actual(),
out_error_msg);
// Clear out |msg| independent of success or failure
BytePart bytes = msg->ReleaseBytesAndHandles();
if (status == ZX_OK) {
Reset(std::move(bytes));
} else {
Reset(BytePart());
}
return status;
}
// Serializes the content of the message in-place and stores the result
// in |out_msg|. The message's contents are always consumed by this
// operation, even in case of an error.
zx_status_t EncodeTo(EncodedMessage<FidlType>* out_msg, const char** out_error_msg) {
return out_msg->Initialize([this, &out_error_msg] (BytePart& msg_bytes,
HandlePart& msg_handles) {
msg_bytes = std::move(bytes_);
uint32_t actual_handles = 0;
zx_status_t status = fidl_encode(FidlType::type,
msg_bytes.data(), msg_bytes.actual(),
msg_handles.data(), msg_handles.capacity(),
&actual_handles, out_error_msg);
msg_handles.set_actual(actual_handles);
return status;
});
}
// Accesses the FIDL message by reinterpreting the buffer pointer.
// Returns nullptr if there is no message.
FidlType* message() const {
return reinterpret_cast<FidlType*>(bytes_.data());
}
private:
// Use the FIDL encoding tables for |FidlType| to walk the message and
// destroy the handles it contains.
void CloseHandles() {
#ifdef __Fuchsia__
if (bytes_.data()) {
fidl_close_handles(FidlType::type, bytes_.data(), bytes_.actual(), nullptr);
}
#endif
}
// The contents of the decoded message.
BytePart bytes_;
};
} // namespace fidl
#endif // LIB_FIDL_LLCPP_DECODED_MESSAGE_H_