| // Copyright 2020 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_MESSAGE_H_ |
| #define LIB_FIDL_LLCPP_MESSAGE_H_ |
| |
| #include <lib/fidl/cpp/message_part.h> |
| #include <lib/fidl/llcpp/result.h> |
| #include <lib/fidl/txn_header.h> |
| |
| #ifdef __Fuchsia__ |
| #include <lib/fidl/llcpp/client_end.h> |
| #include <lib/fidl/llcpp/server_end.h> |
| #include <lib/zx/channel.h> |
| #include <zircon/fidl.h> |
| #endif |
| |
| namespace fidl { |
| |
| namespace internal { |
| |
| #ifdef __Fuchsia__ |
| class ClientBase; |
| class ResponseContext; |
| #endif |
| |
| } // namespace internal |
| |
| // Class representing a FIDL message on the write path. |
| // Each instantiation of the class should only be used for one message. |
| class OutgoingMessage final : public ::fidl::Result { |
| public: |
| // Creates an object which can manage a FIDL message. |bytes| and |handles| will be used as the |
| // destination to linearize and encode the message. At this point, the data within |bytes_| and |
| // |handles_| is undefined. |
| OutgoingMessage(uint8_t* bytes, uint32_t byte_capacity, uint32_t byte_actual, |
| zx_handle_disposition_t* handles, uint32_t handle_capacity, |
| uint32_t handle_actual); |
| explicit OutgoingMessage(const fidl_outgoing_msg_t* msg) |
| : ::fidl::Result(ZX_OK, nullptr), |
| message_(*msg), |
| byte_capacity_(msg->num_bytes), |
| handle_capacity_(msg->num_handles) {} |
| // Copy and move is disabled for the sake of avoiding double handle close. |
| // It is possible to implement the move operations with correct semantics if they are |
| // ever needed. |
| OutgoingMessage(const OutgoingMessage&) = delete; |
| OutgoingMessage(OutgoingMessage&&) = delete; |
| OutgoingMessage& operator=(const OutgoingMessage&) = delete; |
| OutgoingMessage& operator=(OutgoingMessage&&) = delete; |
| ~OutgoingMessage(); |
| |
| uint8_t* bytes() const { return reinterpret_cast<uint8_t*>(message_.bytes); } |
| zx_handle_disposition_t* handles() const { return message_.handles; } |
| uint32_t byte_actual() const { return message_.num_bytes; } |
| uint32_t handle_actual() const { return message_.num_handles; } |
| uint32_t byte_capacity() const { return byte_capacity_; } |
| uint32_t handle_capacity() const { return handle_capacity_; } |
| fidl_outgoing_msg_t* message() { return &message_; } |
| const fidl_outgoing_msg_t* message() const { return &message_; } |
| |
| // Release the handles to prevent them to be closed by CloseHandles. This method is only useful |
| // when interfacing with low-level channel operations which consume the handles. |
| void ReleaseHandles() { message_.num_handles = 0; } |
| |
| // Linearizes and encodes a message. |data| is a pointer to a buffer which holds the source |
| // message body which type is defined by |FidlType|. |
| // If this function succeed: |
| // - |status_| is ZX_OK |
| // - |message_| holds the data for the linearized version of |data|. |
| // If this function fails: |
| // - |status_| is not ZX_OK |
| // - |error_message_| holds an explanation of the failure |
| // - |message_| is undefined |
| template <typename FidlType> |
| void LinearizeAndEncode(FidlType* data) { |
| LinearizeAndEncode(FidlType::Type, data); |
| } |
| |
| #ifdef __Fuchsia__ |
| // Uses zx_channel_write to write the linearized message. |
| // Before calling Write, LinearizeAndEncode must be called. |
| void Write(zx_handle_t channel); |
| |
| // Various helper functions for writing to other channel-like types. |
| |
| void Write(const ::zx::channel& channel) { Write(channel.get()); } |
| |
| void Write(const ::zx::unowned_channel& channel) { Write(channel->get()); } |
| |
| template <typename Protocol> |
| void Write(::fidl::UnownedClientEnd<Protocol> client_end) { |
| Write(client_end.channel()); |
| } |
| |
| template <typename Protocol> |
| void Write(const ::fidl::ServerEnd<Protocol>& server_end) { |
| Write(server_end.channel().get()); |
| } |
| |
| // For requests with a response, uses zx_channel_call to write the linearized message. |
| // Before calling Call, LinearizeAndEncode must be called. |
| // If the call succeed, |result_bytes| contains the decoded linearized result. |
| template <typename FidlType> |
| void Call(zx_handle_t channel, uint8_t* result_bytes, uint32_t result_capacity, |
| zx_time_t deadline = ZX_TIME_INFINITE) { |
| Call(FidlType::Type, channel, result_bytes, result_capacity, deadline); |
| } |
| |
| // Helper function for making a call over other channel-like types. |
| template <typename FidlType, typename Protocol> |
| void Call(::fidl::UnownedClientEnd<Protocol> client_end, uint8_t* result_bytes, |
| uint32_t result_capacity, zx_time_t deadline = ZX_TIME_INFINITE) { |
| Call(FidlType::Type, client_end.channel(), result_bytes, result_capacity, deadline); |
| } |
| |
| // For asynchronous clients, writes a request. |
| ::fidl::Result Write(::fidl::internal::ClientBase* client, |
| ::fidl::internal::ResponseContext* context); |
| #endif |
| |
| private: |
| // Linearizes and encodes a message. |data| is a pointer to a buffer which holds the source |
| // message body which type is defined by |message_type|. |
| // If this function succeed: |
| // - |status_| is ZX_OK |
| // - |message_| holds the data for the linearized version of |data|. |
| // If this function fails: |
| // - |status_| is not ZX_OK |
| // - |error_message_| holds an explanation of the failure |
| // - |message_| is undefined |
| // The handles in the message are always consumed by LinearizeAndEncode. If it succeeds they will |
| // be transferred into |handles_|. If it fails, some handles may be transferred into |handles_| |
| // and the rest will be closed. |
| void LinearizeAndEncode(const fidl_type_t* message_type, void* data); |
| |
| #ifdef __Fuchsia__ |
| // For requests with a response, uses zx_channel_call to write the linearized message. |
| // Before calling Call, LinearizeAndEncode must be called. |
| // If the call succeed, |result_bytes| contains the decoded linearized result. |
| void Call(const fidl_type_t* response_type, zx_handle_t channel, uint8_t* result_bytes, |
| uint32_t result_capacity, zx_time_t deadline); |
| #endif |
| |
| fidl_outgoing_msg_t message_; |
| uint32_t byte_capacity_; |
| uint32_t handle_capacity_; |
| }; |
| |
| namespace internal { |
| |
| // Class representing a FIDL message on the read path. |
| // Each instantiation of the class should only be used for one message. |
| class IncomingMessage : public ::fidl::Result { |
| public: |
| // Creates an object which can manage a FIDL message. Allocated memory is not owned by |
| // the |IncomingMessage|, but handles are owned by it and cleaned up when the |
| // |IncomingMessage| is destructed. |
| // If Decode has been called, the handles have been transferred to the allocated memory. |
| IncomingMessage(); |
| IncomingMessage(uint8_t* bytes, uint32_t byte_actual, zx_handle_info_t* handles, |
| uint32_t handle_actual); |
| explicit IncomingMessage(const fidl_incoming_msg_t* msg) |
| : ::fidl::Result(ZX_OK, nullptr), message_(*msg) {} |
| // Copy and move is disabled for the sake of avoiding double handle close. |
| // It is possible to implement the move operations with correct semantics if they are |
| // ever needed. |
| IncomingMessage(const IncomingMessage&) = delete; |
| IncomingMessage(IncomingMessage&&) = delete; |
| IncomingMessage& operator=(const IncomingMessage&) = delete; |
| IncomingMessage& operator=(IncomingMessage&&) = delete; |
| ~IncomingMessage(); |
| |
| uint8_t* bytes() const { return reinterpret_cast<uint8_t*>(message_.bytes); } |
| zx_handle_info_t* handles() const { return message_.handles; } |
| uint32_t byte_actual() const { return message_.num_bytes; } |
| uint32_t handle_actual() const { return message_.num_handles; } |
| fidl_incoming_msg_t* message() { return &message_; } |
| |
| protected: |
| // Initialize the |IncomingMessage| from an |OutgoingMessage|. The handles within |
| // |OutgoingMessage| are transferred to the |IncomingMessage|. |
| // This is intended only for tests. |
| void Init(OutgoingMessage& outgoing_message, zx_handle_info_t* handles, uint32_t handle_capacity); |
| |
| // Reset the byte pointer. Used to relase the control onwership of the bytes. |
| void ResetBytes() { message_.bytes = nullptr; } |
| |
| // Decodes the message using |FidlType|. If this operation succeed, |status()| is ok and |
| // |bytes()| contains the decoded object. |
| // This method should be used after a read. |
| template <typename FidlType> |
| void Decode() { |
| Decode(FidlType::Type); |
| } |
| |
| private: |
| // Decodes the message using |message_type|. If this operation succeed, |status()| is ok and |
| // |bytes()| contains the decoded object. |
| // This method should be used after a read. |
| void Decode(const fidl_type_t* message_type); |
| |
| // Release the handles to prevent them to be closed by CloseHandles. This method is only useful |
| // when interfacing with low-level channel operations which consume the handles. |
| void ReleaseHandles() { message_.num_handles = 0; } |
| |
| fidl_incoming_msg_t message_; |
| }; |
| |
| } // namespace internal |
| |
| // This class owns a message of |FidlType| and encodes the message automatically upon construction. |
| template <typename FidlType> |
| using OwnedEncodedMessage = typename FidlType::OwnedEncodedMessage; |
| |
| // This class manages the handles within |FidlType| and encodes the message automatically upon |
| // construction. Different from |OwnedEncodedMessage|, it takes in a caller-allocated buffer and |
| // uses that as the backing storage for the message. The buffer must outlive instances of this |
| // class. |
| template <typename FidlType> |
| using UnownedEncodedMessage = typename FidlType::UnownedEncodedMessage; |
| |
| // This class manages the handles within |FidlType| and decodes the message automatically upon |
| // construction. It always borrows external buffers for the backing storage of the message. |
| // This class should mostly be used for tests. |
| template <typename FidlType> |
| using DecodedMessage = typename FidlType::DecodedMessage; |
| |
| // Convert an outgoing message to an incoming message. |
| // |
| // In doing so, it will make syscalls to fetch rights and type information |
| // of any provided handles. The caller is responsible for ensuring that |
| // outputted handle rights and object types are checked appropriately. |
| zx_status_t OutgoingToIncomingMessage(const fidl_outgoing_msg_t* input, |
| zx_handle_info_t* handle_buf, uint32_t handle_buf_count, |
| fidl_incoming_msg_t* output); |
| } // namespace fidl |
| |
| #endif // LIB_FIDL_LLCPP_MESSAGE_H_ |