blob: be11e8dde49801582855affff9378a6c4fbe248c [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 {
template<typename FidlType>
struct DecodeResult;
template <typename FidlType>
DecodeResult<FidlType> Decode(EncodedMessage<FidlType> msg);
template<typename FidlType>
struct EncodeResult;
template <typename FidlType>
class DecodedMessage;
template <typename FidlType>
EncodeResult<FidlType> Encode(DecodedMessage<FidlType> msg);
// `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::PrimarySize > 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);
}
// 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());
}
// Returns true iff the DecodedMessage has a valid message, i.e. non-NULL buffer pointer.
bool is_valid() const {
return bytes_.data() != nullptr;
}
private:
friend DecodeResult<FidlType> Decode<FidlType>(EncodedMessage<FidlType> msg);
friend EncodeResult<FidlType> Encode<FidlType>(DecodedMessage<FidlType> msg);
// Use the FIDL encoding tables for |FidlType| to walk the message and
// destroy the handles it contains.
void CloseHandles() {
// Using the coding table to single out boring types instead of checking
// |FidlType::MaxNumHandle|, to avoid the pathological case where a FIDL message has a
// vector of handles with max count limited at 0, but the user attaches some handles anyway.
if (!NeedsEncodeDecode<FidlType>::value) {
return;
}
#ifdef __Fuchsia__
if (bytes_.data()) {
fidl_close_handles(FidlType::Type, bytes_.data(), nullptr);
}
#endif
}
// The contents of the decoded message.
BytePart bytes_;
};
} // namespace fidl
#endif // LIB_FIDL_LLCPP_DECODED_MESSAGE_H_