1 // Copyright 2016 The Fuchsia Authors 2 // 3 // Use of this source code is governed by a MIT-style 4 // license that can be found in the LICENSE file or at 5 // https://opensource.org/licenses/MIT 6 7 #pragma once 8 9 #include <stdint.h> 10 11 #include <fbl/intrusive_double_list.h> 12 #include <fbl/intrusive_single_list.h> 13 #include <ktl/unique_ptr.h> 14 #include <lib/user_copy/user_ptr.h> 15 #include <object/buffer_chain.h> 16 #include <object/handle.h> 17 #include <zircon/types.h> 18 19 constexpr uint32_t kMaxMessageSize = 65536u; 20 constexpr uint32_t kMaxMessageHandles = 64u; 21 22 // ensure public constants are aligned 23 static_assert(ZX_CHANNEL_MAX_MSG_BYTES == kMaxMessageSize, ""); 24 static_assert(ZX_CHANNEL_MAX_MSG_HANDLES == kMaxMessageHandles, ""); 25 26 class Handle; 27 class MessagePacket; 28 namespace internal { 29 struct MessagePacketDeleter; 30 } // namespace internal 31 32 33 // Definition of a MessagePacket's specific pointer type. Message packets must 34 // be managed using this specific type of pointer, because MessagePackets have a 35 // specific custom deletion requirement. 36 using MessagePacketPtr = ktl::unique_ptr<MessagePacket, internal::MessagePacketDeleter>; 37 38 class MessagePacket final : public fbl::DoublyLinkedListable<MessagePacketPtr> { 39 public: 40 // Creates a message packet containing the provided data and space for 41 // |num_handles| handles. The handles array is uninitialized and must 42 // be completely overwritten by clients. 43 static zx_status_t Create(user_in_ptr<const void> data, uint32_t data_size, 44 uint32_t num_handles, MessagePacketPtr* msg); 45 static zx_status_t Create(const void* data, uint32_t data_size, 46 uint32_t num_handles, MessagePacketPtr* msg); 47 data_size()48 uint32_t data_size() const { return data_size_; } 49 50 // Copies the packet's |data_size()| bytes to |buf|. 51 // Returns an error if |buf| points to a bad user address. CopyDataTo(user_out_ptr<void> buf)52 zx_status_t CopyDataTo(user_out_ptr<void> buf) const { 53 return buffer_chain_->CopyOut(buf, payload_offset_, data_size_); 54 } 55 num_handles()56 uint32_t num_handles() const { return num_handles_; } handles()57 Handle* const* handles() const { return handles_; } mutable_handles()58 Handle** mutable_handles() { return handles_; } 59 set_owns_handles(bool own_handles)60 void set_owns_handles(bool own_handles) { owns_handles_ = own_handles; } 61 62 // zx_channel_call treats the leading bytes of the payload as 63 // a transaction id of type zx_txid_t. get_txid()64 zx_txid_t get_txid() const { 65 if (data_size_ < sizeof(zx_txid_t)) { 66 return 0; 67 } 68 // The first few bytes of the payload are a zx_txid_t. 69 void* payload_start = buffer_chain_->buffers()->front().data() + payload_offset_; 70 return *reinterpret_cast<zx_txid_t*>(payload_start); 71 } 72 set_txid(zx_txid_t txid)73 void set_txid(zx_txid_t txid) { 74 if (data_size_ >= sizeof(zx_txid_t)) { 75 void* payload_start = buffer_chain_->buffers()->front().data() + payload_offset_; 76 *(reinterpret_cast<zx_txid_t*>(payload_start)) = txid; 77 } 78 } 79 80 private: 81 // A private constructor ensures that users must use the static factory 82 // Create method to create a MessagePacket. This, in turn, guarantees that 83 // when a user creates a MessagePacket, they end up with the proper 84 // MessagePacket::UPtr type for managing the message packet's life cycle. MessagePacket(BufferChain * chain,uint32_t data_size,uint32_t payload_offset,uint16_t num_handles,Handle ** handles)85 MessagePacket(BufferChain* chain, uint32_t data_size, uint32_t payload_offset, 86 uint16_t num_handles, Handle** handles) 87 : buffer_chain_(chain), handles_(handles), data_size_(data_size), 88 payload_offset_(payload_offset), num_handles_(num_handles), owns_handles_(false) {} 89 90 // A private destructor helps to make sure that only our custom deleter is 91 // ever used to destroy this object which, in turn, makes it very difficult 92 // to not properly recycle the object. ~MessagePacket()93 ~MessagePacket() { 94 DEBUG_ASSERT(!InContainer()); 95 if (owns_handles_) { 96 for (size_t ix = 0; ix != num_handles_; ++ix) { 97 // Delete the handle via HandleOwner dtor. 98 HandleOwner ho(handles_[ix]); 99 } 100 } 101 } 102 103 friend struct internal::MessagePacketDeleter; 104 static void recycle(MessagePacket* packet); 105 106 static zx_status_t CreateCommon(uint32_t data_size, uint32_t num_handles, 107 MessagePacketPtr* msg); 108 109 BufferChain* buffer_chain_; 110 Handle** const handles_; 111 const uint32_t data_size_; 112 const uint32_t payload_offset_; 113 const uint16_t num_handles_; 114 bool owns_handles_; 115 }; 116 117 namespace internal { 118 struct MessagePacketDeleter { operatorMessagePacketDeleter119 void operator()(MessagePacket* packet) const noexcept { MessagePacket::recycle(packet); } 120 }; 121 } // namespace internal 122 123