1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#ifndef MOJO_SYSTEM_TRANSPORT_DATA_H_ 6#define MOJO_SYSTEM_TRANSPORT_DATA_H_ 7 8#include <stdint.h> 9 10#include <vector> 11 12#include "base/macros.h" 13#include "base/memory/aligned_memory.h" 14#include "base/memory/scoped_ptr.h" 15#include "build/build_config.h" 16#include "mojo/embedder/platform_handle.h" 17#include "mojo/embedder/platform_handle_vector.h" 18#include "mojo/system/dispatcher.h" 19#include "mojo/system/system_impl_export.h" 20 21namespace mojo { 22namespace system { 23 24class Channel; 25 26// This class is used by |MessageInTransit| to represent handles (|Dispatcher|s) 27// in various stages of serialization. 28// 29// The stages are: 30// - Before reaching |TransportData|: Turn |DispatcherTransport|s into 31// |Dispatcher|s that are "owned" by (and attached to) a |MessageInTransit|. 32// This invalidates the handles in the space of the sending application 33// (and, e.g., if another thread is waiting on such a handle, it'll be 34// notified of this invalidation). 35// - Serialize these dispatchers into the |TransportData|: First, for each 36// attached dispatcher, there's an entry in the |TransportData|'s "handle 37// table", which points to a segment of (dispatcher-type-dependent) data. 38// - During the serialization of the dispatchers, |PlatformHandle|s may be 39// detached from the dispatchers and attached to the |TransportData|. 40// - Before sending the |MessageInTransit|, including its main buffer and the 41// |TransportData|'s buffer, the |Channel| sends any |PlatformHandle|s (in a 42// platform-, and possibly sandbox-situation-, specific way) first. In doing 43// so, it appends a "platform handle table" to the |TransportData| 44// containing information about how to deserialize these |PlatformHandle|s. 45// - Finally, at this point, to send the |MessageInTransit|, there only 46// remains "inert" data: the |MessageInTransit|'s main buffer and data from 47// the |TransportData|, consisting of the "handle table" (one entry for each 48// attached dispatcher), dispatcher-type-specific data (one segment for each 49// entry in the "handle table"), and the "platform handle table" (one entry 50// for each attached |PlatformHandle|). 51// 52// To receive a message (|MessageInTransit|), the "reverse" happens: 53// - On POSIX, receive and buffer |PlatformHandle|s (i.e., FDs), which were 54// sent before the "inert" data. 55// - Receive the "inert" data from the |MessageInTransit|. Examine its 56// "platform handle table". On POSIX, match its entries with the buffered 57// |PlatformHandle|s, which were previously received. On Windows, do what's 58// necessary to obtain |PlatformHandle|s (e.g.: i. if the sender is fully 59// trusted and able to duplicate handle into the receiver, then just pick 60// out the |HANDLE| value; ii. if the receiver is fully trusted and able to 61// duplicate handles from the receiver, do the |DuplicateHandle()|; iii. 62// otherwise, talk to a broker to get handles). Reattach all the 63// |PlatformHandle|s to the |MessageInTransit|. 64// - For each entry in the "handle table", use serialized dispatcher data to 65// reconstitute a dispatcher, taking ownership of associated 66// |PlatformHandle|s (and detaching them). Attach these dispatchers to the 67// |MessageInTransit|. 68// - At this point, the |MessageInTransit| consists of its main buffer 69// (primarily the data payload) and the attached dispatchers; the 70// |TransportData| can be discarded. 71// - When |MojoReadMessage()| is to give data to the application, attach the 72// dispatchers to the (global, "core") handle table, getting handles; give 73// the application the data payload and these handles. 74// 75// TODO(vtl): Everything above involving |PlatformHandle|s. 76class MOJO_SYSTEM_IMPL_EXPORT TransportData { 77 public: 78 // The maximum size of a single serialized dispatcher. This must be a multiple 79 // of |kMessageAlignment|. 80 static const size_t kMaxSerializedDispatcherSize = 10000; 81 82 // The maximum number of platform handles to attach for a single serialized 83 // dispatcher. 84 static const size_t kMaxSerializedDispatcherPlatformHandles = 2; 85 86 // The maximum possible size of a valid transport data buffer. 87 static const size_t kMaxBufferSize; 88 89 // The maximum total number of platform handles that may be attached. 90 static const size_t kMaxPlatformHandles; 91 92 TransportData(scoped_ptr<DispatcherVector> dispatchers, Channel* channel); 93 94#if defined(OS_POSIX) 95 // This is a hacky POSIX-only constructor to directly attach only platform 96 // handles to a message, used by |RawChannelPosix| to split messages with too 97 // many platform handles into multiple messages. |Header| will be present, but 98 // be zero. (No other information will be attached, and 99 // |RawChannel::GetSerializedPlatformHandleSize()| should return zero.) 100 explicit TransportData( 101 embedder::ScopedPlatformHandleVectorPtr platform_handles); 102#endif 103 104 ~TransportData(); 105 106 const void* buffer() const { return buffer_.get(); } 107 void* buffer() { return buffer_.get(); } 108 size_t buffer_size() const { return buffer_size_; } 109 110 uint32_t platform_handle_table_offset() const { 111 return header()->platform_handle_table_offset; 112 } 113 114 // Gets attached platform-specific handles; this may return null if there are 115 // none. Note that the caller may mutate the set of platform-specific handles. 116 const embedder::PlatformHandleVector* platform_handles() const { 117 return platform_handles_.get(); 118 } 119 embedder::PlatformHandleVector* platform_handles() { 120 return platform_handles_.get(); 121 } 122 123 // Receive-side functions: 124 125 // Checks if the given buffer (from the "wire") looks like a valid 126 // |TransportData| buffer. (Should only be called if |buffer_size| is 127 // nonzero.) Returns null if valid, and a pointer to a human-readable error 128 // message (for debug/logging purposes) on error. Note: This checks the 129 // validity of the handle table entries (i.e., does range checking), but does 130 // not check that the validity of the actual serialized dispatcher 131 // information. 132 static const char* ValidateBuffer(size_t serialized_platform_handle_size, 133 const void* buffer, 134 size_t buffer_size); 135 136 // Gets the platform handle table from a (valid) |TransportData| buffer (which 137 // should have been validated using |ValidateBuffer()| first). 138 static void GetPlatformHandleTable(const void* transport_data_buffer, 139 size_t* num_platform_handles, 140 const void** platform_handle_table); 141 142 // Deserializes dispatchers from the given (serialized) transport data buffer 143 // (typically from a |MessageInTransit::View|) and vector of platform handles. 144 // |buffer| should be non-null and |buffer_size| should be nonzero. 145 static scoped_ptr<DispatcherVector> DeserializeDispatchers( 146 const void* buffer, 147 size_t buffer_size, 148 embedder::ScopedPlatformHandleVectorPtr platform_handles, 149 Channel* channel); 150 151 private: 152 // To allow us to make compile-assertions about |Header|, etc. in the .cc 153 // file. 154 struct PrivateStructForCompileAsserts; 155 156 // Header for the "secondary buffer"/"transport data". Must be a multiple of 157 // |MessageInTransit::kMessageAlignment| in size. Must be POD. 158 struct Header { 159 uint32_t num_handles; 160 // TODO(vtl): Not used yet: 161 uint32_t platform_handle_table_offset; 162 uint32_t num_platform_handles; 163 uint32_t unused; 164 }; 165 166 struct HandleTableEntry { 167 int32_t type; // From |Dispatcher::Type| (|kTypeUnknown| for "invalid"). 168 uint32_t offset; // Relative to the start of the "secondary buffer". 169 uint32_t size; // (Not including any padding.) 170 uint32_t unused; 171 }; 172 173 const Header* header() const { 174 return reinterpret_cast<const Header*>(buffer_.get()); 175 } 176 177 size_t buffer_size_; 178 scoped_ptr<char, base::AlignedFreeDeleter> buffer_; // Never null. 179 180 // Any platform-specific handles attached to this message (for inter-process 181 // transport). The vector (if any) owns the handles that it contains (and is 182 // responsible for closing them). 183 // TODO(vtl): With C++11, change it to a vector of |ScopedPlatformHandles|. 184 embedder::ScopedPlatformHandleVectorPtr platform_handles_; 185 186 DISALLOW_COPY_AND_ASSIGN(TransportData); 187}; 188 189} // namespace system 190} // namespace mojo 191 192#endif // MOJO_SYSTEM_TRANSPORT_DATA_H_ 193