| // 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_CPP_MESSAGE_H_ |
| #define LIB_FIDL_CPP_MESSAGE_H_ |
| |
| #include <lib/fidl/coding.h> |
| #include <lib/fidl/cpp/message_part.h> |
| #include <lib/fidl/transformer.h> |
| #include <lib/fidl/txn_header.h> |
| #include <zircon/fidl.h> |
| |
| #include <vector> |
| |
| namespace fidl { |
| |
| const fidl_type_t* get_alt_type(const fidl_type_t* type); |
| |
| // This is a higher level wrapper around fidl_transform that is responsible for |
| // allocating memory for the transformed bytes, then calls the provided callback |
| // on the transformed bytes. |
| // |
| // This function will avoid calling fidl_transform whenever possible by checking |
| // the fidl_type_t's contains_union field, and will also stack or heap allocate |
| // depending on the possible size of the output bytes. |
| zx_status_t FidlTransformWithCallback( |
| fidl_transformation_t transformation, const fidl_type_t* type, const uint8_t* src_bytes, |
| uint32_t src_num_bytes, const char** out_error_msg, |
| const std::function<zx_status_t(const uint8_t* dst_bytes, uint32_t dst_num_bytes)>& callback); |
| |
| // A FIDL message. |
| // |
| // A FIDL message has two parts: the bytes and the handles. The bytes are |
| // divided into a header (of type fidl_message_header_t) and a payload, which |
| // follows the header. |
| // |
| // A Message object does not own the storage for the message parts. |
| class Message { |
| public: |
| // Creates a message without any storage. |
| Message(); |
| |
| // Creates a message whose storage is backed by |bytes| and |handles|. |
| // |
| // The constructed |Message| object does not take ownership of the given |
| // storage, although does take ownership of zircon handles contained withing |
| // handles. |
| Message(BytePart bytes, HandlePart handles); |
| |
| ~Message(); |
| |
| Message(const Message& other) = delete; |
| Message& operator=(const Message& other) = delete; |
| |
| Message(Message&& other); |
| Message& operator=(Message&& other); |
| |
| // The header at the start of the message. |
| const fidl_message_header_t& header() const { |
| return *reinterpret_cast<fidl_message_header_t*>(bytes_.data()); |
| } |
| fidl_message_header_t& header() { |
| return *reinterpret_cast<fidl_message_header_t*>(bytes_.data()); |
| } |
| |
| // The transaction ID in the message header. |
| zx_txid_t txid() const { return header().txid; } |
| void set_txid(zx_txid_t txid) { header().txid = txid; } |
| |
| // The ordinal in the message header. |
| uint64_t ordinal() const { return header().ordinal; } |
| |
| // Whether this message is in a supported version of the wire format. |
| bool is_supported_version() const { |
| return fidl_validate_txn_header(GetBytesAs<fidl_message_header_t>()) == ZX_OK; |
| } |
| |
| // The message payload that follows the header. |
| BytePart payload() const { |
| constexpr uint32_t n = sizeof(fidl_message_header_t); |
| return BytePart(bytes_.data() + n, bytes_.capacity() - n, bytes_.actual() - n); |
| } |
| |
| // The message bytes interpreted as the given type. |
| template <typename T> |
| T* GetBytesAs() const { |
| return reinterpret_cast<T*>(bytes_.data()); |
| } |
| |
| // The message payload that follows the header interpreted as the given type. |
| template <typename T> |
| T* GetPayloadAs() const { |
| return reinterpret_cast<T*>(bytes_.data() + sizeof(fidl_message_header_t)); |
| } |
| |
| // The storage for the bytes of the message. |
| BytePart& bytes() { return bytes_; } |
| const BytePart& bytes() const { return bytes_; } |
| void set_bytes(BytePart bytes) { bytes_ = static_cast<BytePart&&>(bytes); } |
| |
| // The storage for the handles of the message. |
| // |
| // When the message is encoded, the handle values are stored in this part of |
| // the message. When the message is decoded, this part of the message is |
| // empty and the handle values are stored in the bytes(). |
| HandlePart& handles() { return handles_; } |
| const HandlePart& handles() const { return handles_; } |
| |
| // Encodes the message in-place. |
| // |
| // The message must previously have been in a decoded state, for example, |
| // either by being built in a decoded state using a |Builder| or having been |
| // decoded using the |Decode| method. |
| zx_status_t Encode(const fidl_type_t* type, const char** error_msg_out); |
| |
| // Decodes the message in-place. |
| // |
| // The message must previously have been in an encoded state, for example, |
| // either by being read from a zx_channel_t or having been encoded using the |
| // |Encode| method. |
| zx_status_t Decode(const fidl_type_t* type, const char** error_msg_out); |
| |
| // Validates the message in-place. |
| // |
| // The message must already be in an encoded state, for example, either by |
| // being read from a zx_channel_t or having been created in that state. |
| // |
| // Does not modify the message. |
| zx_status_t Validate(const fidl_type_t* type, const char** error_msg_out) const; |
| |
| // Read a message from the given channel. |
| // |
| // The bytes read from the channel are stored in bytes() and the handles |
| // read from the channel are stored in handles(). Existing data in these |
| // buffers is overwritten. |
| zx_status_t Read(zx_handle_t channel, uint32_t flags); |
| |
| // Writes a message to the given channel. |
| // |
| // The bytes stored in bytes() are written to the channel and the handles |
| // stored in handles() are written to the channel. |
| // |
| // If this method returns ZX_OK, handles() will be empty because they were |
| // consumed by this operation. |
| zx_status_t Write(zx_handle_t channel, uint32_t flags); |
| |
| // Writes a message to the given channel, possibly transforming it first. |
| // |
| // This method is similar to Write, but also takes in a fidl_type_t |
| // to transform the message (if it contains a union) to the v1 wire format |
| // before sending it. Since FIDL bindings automatically do this, the |
| // WriteTransform method is intended primarily for usecases where FIDL messages |
| // must be send manually. |
| zx_status_t WriteTransformV1(zx_handle_t channel, uint32_t flags, const fidl_type_t* type); |
| |
| // Issues a synchronous send and receive transaction on the given channel. |
| // |
| // The bytes stored in bytes() are written to the channel and the handles |
| // stored in handles() are written to the channel. The bytes read from the |
| // channel are stored in response->bytes() and the handles read from the |
| // channel are stored in response->handles(). |
| // |
| // If this method returns ZX_OK, handles() will be empty because they were |
| // consumed by this operation. |
| zx_status_t Call(zx_handle_t channel, uint32_t flags, zx_time_t deadline, Message* response); |
| |
| // Stop tracking the handles in stored in handles(), without closing them. |
| // |
| // Typically, these handles will be extracted during decode or the |
| // message's destructor, so this function will be unnecessary. However, |
| // for clients of ulib/fidl which decode message manually, this function |
| // is necessary to prevent extracted handles from being closed. |
| void ClearHandlesUnsafe(); |
| |
| private: |
| BytePart bytes_; |
| HandlePart handles_; |
| }; |
| |
| } // namespace fidl |
| |
| #endif // LIB_FIDL_CPP_MESSAGE_H_ |