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